API Reference
Packages
Section titled “Packages”crewlet.ai/v1alpha1
Section titled “crewlet.ai/v1alpha1”Package v1alpha1 contains the v1alpha1 API of the crewlet.ai group: a Crewlet company and its org chart as Kubernetes objects.
Each typed field maps onto one field of Crewlet’s company document, which its doc comment names; enum values are PascalCase here and Crewlet’s own spelling there. Engine tuning without a typed field passes through Company.spec.engineConfig.
No field holds a credential. Every position Crewlet marks as a credential in the company document is filled from a Secret through a SecretKeyReference or a SecretReference (NamespacedSecretKeyReference and NamespacedSecretReference on the cluster-scoped EngineClass), or, for a seat’s account the engine creates under an Integration with provisioning Engine, is a value the engine mints into its own store (ProvisionedCredential). docs/concepts/credentials.md in the repository maps every position to its field.
Resource Types
Section titled “Resource Types”APIExposure
Section titled “APIExposure”APIExposure is how a company’s engine API is reached. Every request needs a credential, but for the probes, the vendors’ webhooks and a sandbox’s per-run endpoints: a person’s session, signed in at the dashboard, or a bearer token, such as the one the operator generates per company and publishes in a Secret named by the Company’s status.apiAccessSecretRef.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
mode APIExposureMode | mode is how the API is reached. | ClusterInternal | Enum: [ClusterInternal Gateway Ingress] Optional: {} |
gateway GatewayExposure | gateway is the Gateways to attach to, for mode Gateway. | Optional: {} | |
ingress IngressExposure | ingress is the Ingress settings, for mode Ingress. | Optional: {} | |
hostname string | hostname is the API’s host name, as a template with the variables and rules of webhooks.hostname, and one rule more. It is also where a browser reaches the engine (the Company’s status.endpoints.dashboardBaseURL, unless the Company states its own), and an origin the engine accepts a person’s write from, and Crewlet refuses to start on a browser’s address whose host ends in a label that is a number: a browser reads such a host as an IPv4 address and rewrites it before it sends it. So its last label may not be one ({{uid}}.123, {{uid}}.0x1f), where webhooks.hostname’s may. A last label a variable fills is a number only for some Companies: one whose namespace is a number (4711, 0x1f) under {{name}}.{{namespace}}, or whose namespace or name makes one with the template’s own characters beside it ({{uid}}.0x{{name}} for a Company named cafe; a Company’s name begins with a letter, so it is never a number alone). That Company’s engine is held back, with RuntimeReady=False AddressRefused, rather than started to refuse. Ending the template in a domain of your own, as in {{name}}.{{namespace}}.crewlet.example.com, leaves it to no Company. | MaxLength: 253 MinLength: 1 Optional: {} |
APIExposureMode
Section titled “APIExposureMode”Underlying type: string
APIExposureMode is how a company’s engine API is reached from outside its namespace.
Validation:
- Enum: [ClusterInternal Gateway Ingress]
Appears in:
| Field | Description |
|---|---|
ClusterInternal | APIExposureClusterInternal reaches the API only through the company’s Service, from inside the cluster. |
Gateway | APIExposureGateway also routes a host name to the API with an HTTPRoute. Attach it to an internal Gateway: the API includes the company’s configuration and secret store. |
Ingress | APIExposureIngress does the same with an Ingress. |
AppliedObjectCounts
Section titled “AppliedObjectCounts”AppliedObjectCounts is how many objects of each kind the applied revision was rendered from.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
units integer | units is the number of Units. | Minimum: 0 Optional: {} | |
seats integer | seats is the number of Seats. | Minimum: 0 Optional: {} | |
llmProviders integer | llmProviders is the number of model providers, platform providers included. | Minimum: 0 Optional: {} | |
mcpServers integer | mcpServers is the number of MCPServers. | Minimum: 0 Optional: {} | |
integrations integer | integrations is the number of Integrations. | Minimum: 0 Optional: {} | |
schedules integer | schedules is the number of Schedules. | Minimum: 0 Optional: {} |
ArtifactExposure
Section titled “ArtifactExposure”ArtifactExposure is how browsers reach the engine’s artifact listener (Crewlet’s api.artifacts), which serves artifacts and nothing else. Crewlet refuses it over plain http on a routable host, so a route serves https only.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
mode ArtifactExposureMode | mode is how the artifact origin is reached. | None | Enum: [None Gateway Ingress] Optional: {} |
gateway GatewayExposure | gateway is the Gateways to attach to, for mode Gateway; a listener the route attaches to must be HTTPS. | Optional: {} | |
ingress IngressExposure | ingress is the Ingress settings, for mode Ingress; tls is required. | Optional: {} | |
hostname string | hostname is the artifact origin’s host name, a template with the variables and rules of api.hostname. Use a registrable domain of its own: on the dashboard’s site Crewlet serves every artifact opaque. | MaxLength: 200 MinLength: 1 Optional: {} | |
origins ArtifactOrigins | origins is PerArtifact (unset), where the route takes *. Shared, where it takes | Enum: [PerArtifact Shared] Optional: {} |
ArtifactExposureMode
Section titled “ArtifactExposureMode”Underlying type: string
ArtifactExposureMode is how browsers reach a company’s artifact origin.
Validation:
- Enum: [None Gateway Ingress]
Appears in:
| Field | Description |
|---|---|
None | ArtifactExposureNone routes nothing; the Company may state an address (spec.exposure.artifactsBaseURL). |
Gateway | ArtifactExposureGateway routes the artifact hosts with an HTTPRoute. |
Ingress | ArtifactExposureIngress does the same with an Ingress. |
ArtifactOrigins
Section titled “ArtifactOrigins”Underlying type: string
ArtifactOrigins is how artifacts are kept apart in a browser.
Validation:
- Enum: [PerArtifact Shared]
Appears in:
| Field | Description |
|---|---|
PerArtifact | ArtifactOriginsPerArtifact gives each artifact a host under the route’s host name: its own origin, which needs a wildcard DNS name and certificate. |
Shared | ArtifactOriginsShared serves every artifact from one host, each with an opaque origin and no browser storage. |
AtlassianIntegration
Section titled “AtlassianIntegration”AtlassianIntegration connects a company’s Atlassian Cloud organization, in which the engine creates a service account for each agent seat, grants it the company’s Jira and Confluence sites, and mints its API token. It maps onto Crewlet’s integrations.atlassian. Each seat names the minted token and the account’s address as provisioned values of its MCPServer named atlassian, so the Integration’s provisioning is Engine. A Data Center deployment has no organization; its accounts are made by hand and each seat’s token comes from a Secret.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
orgID string | orgID is the organization’s id, from admin.atlassian.com. Crewlet’sorg_id. | MaxLength: 64 MinLength: 1 Pattern: ^[A-Za-z0-9-]+$ Required: {} | |
apiKeySecretRef SecretKeyReference | apiKeySecretRef is the Secret key holding an organization API key created without scopes: Atlassian refuses a scoped key the call that creates an account. Crewlet’s api_key, a credential position. | Required: {} |
CLIAgentAuth
Section titled “CLIAgentAuth”CLIAgentAuth is how a CLIAgent provider signs in. It maps onto Crewlet’s cli.auth.
A subscription login is made at a terminal, by crewlet llm login or the
CLI’s own command, and a pod has no terminal: Subscription signs in with a
headless token, such as the CLAUDE_CODE_OAUTH_TOKEN claude setup-token
mints, or with a credential bundle crewlet llm export wrote from a login
made elsewhere: the CLI’s login, which is its credential files, or, for
OpenCode, which keeps its logins in a database of its own, the document
OpenCode 2’s auth export printed. A bundle is restored only while the
provider’s login on the data volume is empty, so the refreshed login a
running engine keeps there wins over the bundle; a token never needs
refreshing, which makes it the better of the two wherever the CLI mints
one. A provider names one of the two: given both, which login the CLI acts
on would be the CLI’s choice between its environment and its own files,
which nothing here can see.
Crewlet hands a CLI a token or a key only through the variable its profile names, and refuses one for a CLI whose profile names none, since it would reach nothing: so CLIAgentSettings holds tokenSecretRef to the CLIs with a token variable and mode APIKey to the CLIs with a key variable.
Hermes, Pi and OpenCode may sign in to a Subscription with neither: each fronts many model providers and reads each provider’s key from that provider’s own variable, so Crewlet’s profile for it names no key variable and marks it as signing in through its environment (env_sign_in), and Crewlet documents the provider’s key in the cli block’s env as its metered sign-in, and hands that env to the CLI untouched. Crewlet counts an entry of env as a sign-in only when its name says it holds a credential: one of its parts between underscores is, in any case, KEY, KEYS, APIKEY, ACCESSKEY, SECRETKEY, TOKEN, SECRET, PASSWORD, PASSWD, CREDENTIAL, CREDENTIALS, AUTH, OAUTH or PAT (cliprofile.IsCredentialName). So OPENROUTER_API_KEY signs such a CLI in and HTTPS_PROXY or HERMES_MAX_TOKENS does not, and one whose env holds no such name is signed in to nothing, and refused. Every other CLI keeps to a token or a bundle: one with a key variable takes its key through mode APIKey, and Crewlet refuses that variable in env, which auth owns. The rule is CLIAgentSettings’s, which sees the agent and env beside auth.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
mode CLIAgentAuthMode | mode is how the CLI signs in. Unset is Subscription. Crewlet’smode. | Enum: [Subscription APIKey] Optional: {} | |
tokenSecretRef SecretKeyReference | tokenSecretRef is the Secret key holding a long-lived subscription token the CLI mints for headless use. Crewlet’s token, a credentialposition. | Optional: {} | |
credentialBundleSecretRef SecretKeyReference | credentialBundleSecretRef is the Secret key holding a credential bundle crewlet llm export wrote. A bundle holding a login OpenCode1.x made (its auth.json) is refused when the engine restores it, and the provider runs signed out: export it again from OpenCode 2. Crewlet’s credential_bundle, a credential position. | Optional: {} |
CLIAgentAuthMode
Section titled “CLIAgentAuthMode”Underlying type: string
CLIAgentAuthMode is how a CLIAgent provider authenticates. It maps onto
Crewlet’s cli.auth.mode (Subscription is subscription, APIKey is
api-key).
Crewlet’s inherit-env, which hands the CLI whichever token or key the
engine’s own environment holds, is not offered: a credential in the
engine’s environment is outside the encrypted store, readable by every
process the engine runs, and resolvable by a ${NAME} written in many fields
of the company document, so it would be the one credential the API takes by
another route than a Secret reference. Subscription and APIKey cover what
it is for.
Validation:
- Enum: [Subscription APIKey]
Appears in:
| Field | Description |
|---|---|
Subscription | CLIAgentAuthSubscription signs the CLI in to a subscription with tokenSecretRef or credentialBundleSecretRef, or signs Hermes, Pi or OpenCode in with its model provider’s key in the cli block’s env. |
APIKey | CLIAgentAuthAPIKey gives the CLI the provider’s apiKeySecretRefs key, in the key variable Crewlet’s profile for it names, billing the metered account. CursorAgent’s key is a Cursor account’s API key (CURSOR_API_KEY), not a model provider’s. |
CLIAgentMode
Section titled “CLIAgentMode”Underlying type: string
CLIAgentMode is how the engine uses the CLI. It maps onto Crewlet’s
cli.mode (Text is text, Agent is agent).
Validation:
- Enum: [Text Agent]
Appears in:
| Field | Description |
|---|---|
Text | CLIAgentModeText drives the CLI as a text model behind the engine’s own tool loop, as a process in the engine’s pod. |
Agent | CLIAgentModeAgent runs a seat’s executor as the CLI’s own agentic run, in a sandbox, with the seat’s tools reached back through the engine’s tool bridge. It is offered for the CLIs Crewlet has a sandbox runner for, ClaudeCode and OpenCode. |
CLIAgentName
Section titled “CLIAgentName”Underlying type: string
CLIAgentName is which coding CLI a CLIAgent provider drives. It maps onto
Crewlet’s cli.agent (ClaudeCode is claude-code, Codex is codex,
GeminiCLI is gemini-cli, QwenCode is qwen-code, OpenCode is opencode,
CursorAgent is cursor-agent, Copilot is copilot, Grok is grok,
MuseCode is muse-code, KimiCode is kimi-code, Hermes is hermes, Pi is
pi). Crewlet’s custom, a CLI described wholly by profile overrides, is
not offered: the overrides name the binary and the arguments the engine’s
pod runs.
Validation:
- Enum: [ClaudeCode Codex GeminiCLI QwenCode OpenCode CursorAgent Copilot Grok MuseCode KimiCode Hermes Pi]
Appears in:
| Field | Description |
|---|---|
ClaudeCode | |
Codex | |
GeminiCLI | |
QwenCode | |
OpenCode | |
CursorAgent | |
Copilot | |
Grok | |
MuseCode | |
KimiCode | |
Hermes | |
Pi |
CLIAgentRunIn
Section titled “CLIAgentRunIn”Underlying type: string
CLIAgentRunIn is where an Agent-mode run happens. It maps onto Crewlet’s
cli.run_in (E2B is e2b). Crewlet’s local cells, direct and container,
are not offered, as the Company’s spec.sandbox does not offer them.
Validation:
- Enum: [E2B]
Appears in:
| Field | Description |
|---|---|
E2B | CLIAgentRunInE2B is the Company’s E2B sandbox. |
CLIAgentSettings
Section titled “CLIAgentSettings”CLIAgentSettings is the coding CLI a CLIAgent provider drives. It maps onto Crewlet’s providers.llm entry’s cli block.
The CLI is a binary in the engine’s image, which the official image does not ship: a class running such a provider names an image derived from the engine’s with the CLI installed (docs/guides/cli-agents.md). For OpenCode that is OpenCode 2, the @opencode/cli package: Crewlet drives no other release, and every command it runs carries —standalone, which OpenCode 1.x (npm’s opencode-ai) rejects. Its login, and the per-seat homes the CLI keeps, are on the data volume, so a restart or a new pod keeps them.
Its rules hold every credential to a variable Crewlet’s profile for the CLI reads, as Crewlet’s own admission does (providers.llm.*.cli): the engine refuses a write that names a credential its CLI would never be given, so the API refuses it on the object instead. The lists of CLIs the rules name are those whose profiles set token_env, api_key_env or env_sign_in in the engine the operator is tested against, Crewlet’s main; a test holds them to that engine’s own verdict. The rules also keep env off the variables Crewlet sets on every call to keep each seat’s CLI inside its own home and its call’s working directory (HOME, the XDG directories, TMPDIR, and the configuration directory or switch each CLI’s profile names in config_env, work_config_env and isolation_env): env is layered over them, so a value there would replace that isolation for every seat on the provider, and Crewlet refuses the document. A test holds that list to the engine’s refusals too.
Mode Agent runs the CLIs Crewlet has a sandbox runner for, ClaudeCode and OpenCode: the Company’s coding agents. Crewlet hands an Agent-mode run its provider’s model exactly as the provider’s text calls pass it (the reviewer’s, a delegated worker’s, the summariser’s), so one model serves every phase. The run happens in the Company’s E2B sandbox, which never receives a credential bundle: the bundle’s login carries a refresh token the engine keeps rotating on its data volume. So a Subscription login reaches the run only as a variable of its environment, which for ClaudeCode is its headless token and for OpenCode its model provider’s key in env.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
agent CLIAgentName | agent is which CLI to drive. The provider’s model is written as this CLI reads it, and an Agent-mode run is handed it unchanged: OpenCode reads <provider>/<model>, such as anthropic/claude-sonnet-5.Crewlet’s agent. | Enum: [ClaudeCode Codex GeminiCLI QwenCode OpenCode CursorAgent Copilot Grok MuseCode KimiCode Hermes Pi] Required: {} | |
mode CLIAgentMode | mode is how the engine uses the CLI. Unset is Text. Crewlet’s mode. | Enum: [Text Agent] Optional: {} | |
runIn CLIAgentRunIn | runIn is where an Agent-mode run happens. Unset is the Company’s sandbox, which is E2B. Crewlet’s run_in. | Enum: [E2B] Optional: {} | |
auth CLIAgentAuth | auth is how the CLI signs in. | MinProperties: 1 Required: {} | |
env SecretEnvVar array | env is extra environment of the CLI where it runs in the engine’s pod, as a model behind the engine’s own tool loop: in every phase a Text-mode provider runs, and in every phase but the executor’s of an Agent-mode one. There the CLI does not get the engine’s environment: it gets the part Crewlet’s allowlist names, such as PATH and the TLS and proxy variables, and the variables the CLI’s Crewlet profile passes through, such as GeminiCLI’s GOOGLE_CLOUD_PROJECT, with a HOME, a TMPDIR and XDG directories of its seat’s own rather than the engine’s. So a variable the CLI needs beyond that is given here. It is how Hermes, Pi and OpenCode sign in under auth mode Subscription with no login of their own: their model provider’s key, under a name Crewlet reads as a credential, such as OPENROUTER_API_KEY. It may not set the CLI’s own token or key variable, which auth owns, nor a variable Crewlet sets to keep the CLI inside its seat’s home and its call’s working directory: HOME, the XDG directories, TMPDIR, and the CLI’s own configuration directory or switch (docs/guides/cli-agents.md). An Agent-mode run, and a seat’s code work on the provider, run the CLI in the Company’s E2B sandbox. There it gets none of that environment, and of env only an OpenCode provider’s credential-named variables, where the coding agent can read them; a variable of no credential that such a run needs goes in the Seat’s spec.sandbox.env. Crewlet’s env,a credential position. | MaxItems: 32 Optional: {} | |
timeoutSeconds integer | timeoutSeconds caps one invocation of the CLI, launch included. Unset takes Crewlet’s default of 300. Crewlet’s timeout_seconds. | Minimum: 1 Optional: {} | |
maxConcurrent integer | maxConcurrent is how many CLI processes the provider runs at once; each takes 200 to 450 MB of the engine pod’s memory, OpenCode’s at the top of that range (docs/guides/cli-agents.md). Unset takes Crewlet’s default of 4. Crewlet’s max_concurrent. | Maximum: 64 Minimum: 1 Optional: {} | |
loginName string | loginName names the login, and the per-seat homes, the provider keeps on the data volume. Providers of the company with the same loginName share one login, which is how several models run off one subscription; they must drive the same CLI. Unset is the provider’s own metadata.name. Crewlet’s state_dir, as/var/lib/crewlet/llm-cli/ | MaxLength: 63 MinLength: 1 Pattern: ^[a-z0-9][a-z0-9-]*$ Optional: {} |
ClassEnvVar
Section titled “ClassEnvVar”ClassEnvVar is an environment variable an EngineClass sets on the engine pods of every Company of the class: platform wiring such as the address of the platform’s own API. A value from a Secret is copied by the operator into a Secret it owns in each Company’s namespace and referenced from the pod, as telemetry headers are, so the value never appears in the pod template and the platform’s Secret never has to be readable from a tenant namespace. The value is in every tenant’s engine pod all the same, where code the tenant runs can read it: put nothing here a tenant must not hold.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name is the variable’s name. | MaxLength: 128 MinLength: 1 Pattern: ^[A-Za-z_][A-Za-z0-9_]*$ Required: {} | |
value string | value is the variable’s literal value. An empty string is a valid value, which is why the field is a pointer. | MaxLength: 4096 Optional: {} | |
valueFrom NamespacedSecretValueSource | valueFrom reads the value from a Secret key in a namespace the platform controls. | Optional: {} |
ClaudeModelID
Section titled “ClaudeModelID”Underlying type: string
ClaudeModelID is one id of Crewlet’s table of Claude models, which records the request shape each model accepts (its thinking mode, its effort levels, whether it takes a sampling parameter, its output cap). An Anthropic provider whose model is a gateway alias names the row it is an alias of. Crewlet refuses on every write a claude_model its table does not list, exactly as written, so the values are the table’s ids in the engine the operator is tested against, Crewlet’s main; a test holds them to that engine’s refusal.
Validation:
- Enum: [claude-fable-5-1 claude-mythos-5-1 claude-fable-5 claude-mythos-5 claude-opus-5-5 claude-opus-5 claude-opus-4-8 claude-opus-4-7 claude-sonnet-5-5 claude-sonnet-5 claude-opus-4-6 claude-sonnet-4-6 claude-opus-4-5 claude-sonnet-4-5 claude-haiku-4-5 claude-opus-4-1 claude-opus-4-0 claude-opus-4 claude-sonnet-4-0 claude-sonnet-4 claude-3-7-sonnet]
Appears in:
CodingAgent
Section titled “CodingAgent”Underlying type: string
CodingAgent is the coding agent a sandbox runs. It maps onto Crewlet’s
coding agents (ClaudeCode is claude-code, OpenCode is opencode).
Validation:
- Enum: [ClaudeCode OpenCode]
Appears in:
| Field | Description |
|---|---|
ClaudeCode | CodingAgentClaudeCode is Claude Code. |
OpenCode | CodingAgentOpenCode is OpenCode. |
Company
Section titled “Company”Company is one Crewlet company: the operator runs an engine for it and keeps the engine’s company document equal to what the Company and the objects that name it declare.
The Company’s name becomes part of the names of the objects the operator creates for it (the data StatefulSet and the engine Service), so it must be a DNS label of at most 47 characters: a StatefulSet name longer than 52 characters overflows its pods’ controller-revision-hash label.
| Field | Description | Default | Validation |
|---|---|---|---|
apiVersion string | crewlet.ai/v1alpha1 | ||
kind string | Company | ||
metadata ObjectMeta | Refer to Kubernetes API documentation for fields of metadata. | Optional: {} | |
spec CompanySpec | spec is the company’s desired state. | Required: {} | |
status CompanyStatus | status is the company’s observed state. | MinProperties: 1 Optional: {} |
CompanyEndpoints
Section titled “CompanyEndpoints”CompanyEndpoints is where a company is reached. Every address is a base URL with its scheme, so that a caller appends a path to it and never reconstructs one from the EngineClass’s templates.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
api string | api is the in-cluster base URL of the engine’s API: the company’s Service, for callers inside the cluster. | MaxLength: 2048 MinLength: 1 Optional: {} | |
exposedAPI string | exposedAPI is the base URL of the engine’s API through the class’s exposure.api, for callers outside the cluster: https:// when the route terminates TLS (the Ingress has tls, or the Gateway listener the route attaches to is HTTPS), http:// with the hostname template expanded. Set only while exposure.api.mode is Gateway or Ingress and the route has been accepted. | MaxLength: 2048 MinLength: 1 Optional: {} | |
publicBaseURL string | publicBaseURL is the address vendors deliver webhooks to, when the company has one: spec.exposure.publicBaseURL, or https:// from the class’s webhooks.hostname. It reaches the engine’s public listener, and every vendor route is a path under it, such as /webhooks/forge for an Atlassian Forge relay. Unset while the class’s webhooks.mode is None, which exposes nothing, and under External before the Company states its address: the engine is then told the listener’s address inside the cluster, http:// | MaxLength: 2048 MinLength: 1 Optional: {} | |
dashboardBaseURL string | dashboardBaseURL is where a browser reaches the engine, its dashboard and its people’s sign-in: spec.exposure.dashboardBaseURL, else the address of the class’s API route, on the scheme exposedAPI takes, else http://localhost:8080, the address kubectl port-forward serves the engine Service’s API port at. It does not wait for the route to be accepted, as exposedAPI does: it is the engine’s api.external_url, which the engine reads only at start, and a flip of acceptance would otherwise restart the data pod. The engine builds every link a person follows on it, an invitation’s included, so with the third these lead to a localhost only a port-forwarding browser reaches. | MaxLength: 2048 MinLength: 1 Optional: {} | |
artifactsBaseURL string | artifactsBaseURL is where a browser reaches the artifact origin: spec.exposure.artifactsBaseURL, else the class’s artifacts route while it serves https. Unset, the data pod opens no artifact listener. | MaxLength: 2048 MinLength: 1 Optional: {} |
CompanyExposure
Section titled “CompanyExposure”CompanyExposure overrides how a company is reached.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
publicBaseURL string | publicBaseURL is the HTTPS address vendors deliver webhooks to, and a remote sandbox calls the engine back on, overriding the one the class’s webhooks.hostname derives. Required when the class’s webhooks.mode is External, where something outside the operator (a relay, an API gateway) forwards it to the engine’s public listener. A trailing ’/‘ is dropped, as Crewlet drops it. Crewlet’s api.public.external_url, in the data pod’s crewlet.yaml, which the engine reads only at start: changing it restarts the data pod. Its host is a name, an IPv4 address or an IPv6 address in brackets, followed by at most one port, 1 to 65535: Crewlet refuses to start on any other, but for an IPv6 address whose zone holds a ’]’ (https://[fe80::1%25eth0]]/), which it starts on and no vendor reaches. The API judges the host and the port itself rather than leaving them to the API server’s URL parser, which is Go’s net/url as the API server was built and is run: it takes such a zone, and under Go’s GODEBUG setting urlstrictcolons=0 https://h.example:80:80 too. | MaxLength: 2048 MinLength: 1 Optional: {} | |
dashboardBaseURL string | dashboardBaseURL is where a browser reaches the engine: its dashboard, and the sign-in of the company’s people. It overrides the address of the class’s API route: set it when the class routes no API, or people reach it through something in front of the route (a single sign-on proxy, say). Crewlet’s api.external_url, in the data pod’s crewlet.yaml, which the engine reads only at start: changing it restarts the data pod. The engine takes from it the origin a person’s write must come from, whether the session cookie is Secure (https) and its scope, and the base of every link a person follows: a link an agent composes, an invitation (/dashboard#/invite/…), a password link. An address other than the route’s must serve the engine, its /dashboard and its /auth routes included. The route, when the class has one, stays an origin the engine accepts. It is never the public address: the public listener serves no dashboard. A trailing ’/’ is dropped. Crewlet compares the origin of a person’s write with this address as a browser spells it, and refuses to start on an address whose host a browser rewrites before it sends it, so the API refuses it too: a host outside ASCII, as it is or percent-encoded (write its xn— form, https://xn—bcher-kva.example for https://bücher.example), a host whose last label is a number and that is not an IPv4 address of four decimal octets (127.1, 2130706433, 0x7f.0.0.1, 192.168.010.1, crewlet.123: write 127.0.0.1, or a name that ends in a word), and an IPv6 address with a zone ([fe80::1%25eth0]). Its host is a name, an IPv4 address or an IPv6 address in brackets, followed by at most one port, 1 to 65535 (http://[::1]:8080, not http://::1:8080), which the API judges itself, as for publicBaseURL. | MaxLength: 2048 MinLength: 1 Optional: {} | |
artifactsBaseURL string | artifactsBaseURL is where a browser reaches the artifact origin, ahead of the class’s artifacts route: a tunnel, or http://localhost:8082 for a browser that port-forwards it. Crewlet’s api.artifacts.external_url; changing it restarts the data pod. https, or http on localhost or 127.x.x.x; {artifact} at the start of the host gives each artifact a host of its own. It may not be the dashboard’s or the public listener’s origin, nor a parent of either’s host (RuntimeReady=False AddressRefused). | MaxLength: 2048 MinLength: 1 Optional: {} |
CompanyIntegrationSettings
Section titled “CompanyIntegrationSettings”CompanyIntegrationSettings is company-wide behaviour of the integration reconcile loop. The vendors themselves are Integration objects.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
checkIntervalSeconds integer | checkIntervalSeconds is how long a working integration is trusted before the engine reads it back, and so how long access revoked at the vendor goes unnoticed. Unset takes Crewlet’s default of 600. Crewlet’s integrations.check_interval_seconds. | Minimum: 60 Optional: {} |
CompanyLLMSettings
Section titled “CompanyLLMSettings”CompanyLLMSettings is how a company chooses among its model providers.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
order LLMProviderReference array | order is the providers’ precedence. A seat with no default chain runs on the first provider here, and on it alone: Crewlet tries no other provider of the order when its keys are all cooling down, so give a seat a chain for a fallback. The providers the order leaves out follow it: the company’s LLMProviders by name, then the platform providers by name. Crewlet’s providers.llm_order. | MaxItems: 32 Optional: {} | |
usePlatformProviders boolean | usePlatformProviders adds the EngineClass’s platformLLMProviders to the company, so seats can run on models the platform provides. Their keys are pushed into the company’s engine, where the tenant can read them (see the class’s platformLLMProviders). | Optional: {} |
CompanyObjects
Section titled “CompanyObjects”CompanyObjects is a company’s own access to its class’s object store.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
credentialsSecretRef SecretReference | credentialsSecretRef is a Secret, in the Company’s namespace, holding the keys accessKeyID and secretAccessKey (S3AccessKeyIDKey, S3SecretAccessKeyKey) the engine reaches its class’s S3 bucket with: Crewlet’s store.objects.s3.access_key_id and secret_access_key. Used only while the class’s objects.backend is S3. Issue them per company, with a policy that admits the company’s own prefix of the bucket only (the class’s objects.s3.prefix, expanded): they are written into the engine pod’s crewlet.yaml, and code the tenant runs in the pod (a stdio MCP server, a coding CLI) can read them. Unset uses the pod’s own credentials through the SDK’s default chain: a workload identity bound through the class’s serviceAccount.annotations, which every company of the class shares unless it is scoped per tenant. | Optional: {} |
CompanyReference
Section titled “CompanyReference”CompanyReference names the Company a namespaced object belongs to. The Company is always in the referring object’s own namespace: an object can be part of exactly one company, and a reference across namespaces would let one tenant attach objects to another’s company.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name is the metadata.name of a Company in this object’s namespace. | MaxLength: 253 MinLength: 1 Required: {} |
CompanyRuntime
Section titled “CompanyRuntime”CompanyRuntime is a company’s bounded overrides of its class.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
version string | version replaces the tag of the class’s engine image, for example v1.2.4. It is honoured only when the class sets engine.allowVersionOverride; the operator refuses a version older than the one the company’s data was last written by. | MaxLength: 128 MinLength: 1 Pattern: ^[A-Za-z0-9_][A-Za-z0-9_.-]\{0,127\}$ Optional: {} | |
env EnvVar array | env adds environment variables to the engine container, for platform wiring the engine reads from its environment. They are merged over the class’s podTemplate.spec.env by name: a variable here replaces the class’s variable of the same name. They are the engine’s environment, not that of the processes it starts: a Stdio tool server is handed only the part Crewlet’s allowlist names, such as PATH and the TLS and proxy variables, a coding CLI that part and the variables its Crewlet profile passes through, such as GeminiCLI’s GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION, and a sandbox run none of it. So a variable a tool server reads goes in its MCPServer’s env (docs/guides/tool-servers.md), and any other a coding CLI reads in its LLMProvider’s spec.cli.env. Names starting with CREWLET_ or OTEL_ are the operator’s own. ANTHROPIC_API_KEY and OPENAI_API_KEY are refused too: Crewlet reads them as the key of a model or embeddings provider that names none, so a value here would be a credential outside the engine’s secret store; give the provider its key with apiKeySecretRefs or apiKeySecretRef. | MaxItems: 32 Optional: {} |
CompanySpec
Section titled “CompanySpec”CompanySpec is a company: the engine that runs it and the company-wide part of its document. Its units, seats, model providers, tool servers and integrations are objects of their own that name the Company in their spec.companyRef.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
engineClassName string | engineClassName is the EngineClass the company runs with. Unset uses the class annotated crewlet.ai/is-default-class=true. Whoever may write a Company may name any class, including one that offers platformLLMProviders or larger limits; a class admits only the namespaces its spec.allowedNamespaces selects, and a Company in any other is not accepted (ClassNotAllowed). | MaxLength: 253 MinLength: 1 Optional: {} | |
companyName string | companyName is the company’s name. Crewlet derives every seat’s identity from it and the seat’s handle, so it cannot be changed: a new name would orphan every seat’s memory. Crewlet’s name. | MaxLength: 256 MinLength: 1 Required: {} | |
mission string | mission is one line on what the company is for; every seat’s prompt carries it. Crewlet’s mission. | MaxLength: 2048 MinLength: 1 Optional: {} | |
vision string | vision is a longer statement of where the company is going. Crewlet’svision. | MaxLength: 8192 MinLength: 1 Optional: {} | |
policies string array | policies are company-wide rules every seat’s prompt carries. Crewlet’spolicies. | MaxItems: 64 items:MaxLength: 2048 items:MinLength: 1 Optional: {} | |
timeZone string | timeZone is the company’s clock, an IANA time zone such as Europe/Berlin: where its days begin for budgets, due dates and schedules. Unset is UTC. Crewlet’s timezone. | MaxLength: 64 MinLength: 1 Pattern: ^[A-Za-z][A-Za-z0-9_+-]*(/[A-Za-z0-9_+-]+)*$ Optional: {} | |
tracker TrackerSettings | tracker is which work tracker the company runs. | MinProperties: 1 Optional: {} | |
knowledge KnowledgeSettings | knowledge is which knowledge base the company runs. | MinProperties: 1 Optional: {} | |
tokenBudget TokenBudget | tokenBudget caps the tokens all seats together may spend per window. Crewlet’s token_budget. | MinProperties: 1 Optional: {} | |
llm CompanyLLMSettings | llm is how the company chooses among its model providers. | MinProperties: 1 Optional: {} | |
embeddings EmbeddingSettings | embeddings is the provider vectors are computed with. Unset leaves search keyword-only. Crewlet’s providers.embeddings. | Optional: {} | |
sandbox SandboxSettings | sandbox is where seats run code. Unset gives no seat a sandbox. Crewlet’s providers.sandbox. | Optional: {} | |
integrations CompanyIntegrationSettings | integrations is company-wide integration behaviour. | MinProperties: 1 Optional: {} | |
engineConfig EngineConfigEntry array | engineConfig is passed through into the company document as written, for the engine’s tuning blocks that have no field here: turn_engine, learning, scheduling, workers, skill_variables and the notification_* settings, spelled as Crewlet spells them. Each entry is one top-level key of the document and its value. The operator does not interpret it; the engine validates it in the dry run before every apply, and a refusal is reported on the Company. It may not set what another field or object of this API owns: name, mission, vision, policies, timezone, tracker, knowledge, token_budget, providers, integrations, mcp_servers, roles or units. Every position Crewlet holds a credential in lives under one of those keys, so engineConfig can never carry a credential: the API server refuses a Company whose engineConfig names one of them, before anything is stored. | MaxItems: 64 Optional: {} | |
config ConfigSettings | config is how the operator manages the company’s document. | { managementPolicy:Enforce } | MinProperties: 1 Optional: {} |
topology CompanyTopology | topology is how the engine is laid out in pods. | { data:map[replicas:1] } | MinProperties: 1 Optional: {} |
exposure CompanyExposure | exposure overrides how the company is reached. | MinProperties: 1 Optional: {} | |
runtime CompanyRuntime | runtime is the company’s bounded overrides of its class. | MinProperties: 1 Optional: {} | |
objects CompanyObjects | objects is the company’s own access to its class’s object store. | MinProperties: 1 Optional: {} | |
suspend boolean | suspend stops the engine and keeps its data volumes; setting it back to false starts it again. It takes effect whatever else is wrong with the Company, even while it is not Accepted. Meanwhile the Company reports Ready=False with the reason Suspended, and vendors keep delivering webhooks, some disabling a subscription after a long run of failed deliveries. | Optional: {} | |
deletionPolicy DeletionPolicy | deletionPolicy is what happens to the data volumes when the Company is deleted. With Retain the keyring Secret is kept as well, since the volumes cannot be read without it. | Retain | Enum: [Retain Delete] Optional: {} |
CompanyStatus
Section titled “CompanyStatus”CompanyStatus is what the operator observed about a Company.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
conditions Condition array | conditions are Ready (the summary), Accepted, RuntimeReady, SecretsSynced, ConfigApplied and Exposed, which Ready summarizes, and EngineHealthy, IdentityClaimed and SeatsPlaced, which it does not. | MaxItems: 16 Optional: {} | |
observedGeneration integer | observedGeneration is the metadata.generation this status describes. | Minimum: 1 Optional: {} | |
engine EngineStatus | engine is what runs the company. | MinProperties: 1 Optional: {} | |
topology TopologyStatus | topology is the state of the company’s pods. | MinProperties: 1 Optional: {} | |
config ConfigStatus | config is the revision the engine runs. | MinProperties: 1 Optional: {} | |
endpoints CompanyEndpoints | endpoints is where the company is reached. | MinProperties: 1 Optional: {} | |
apiAccessSecretRef SecretReference | apiAccessSecretRef names the Secret, in the Company’s namespace, that holds a bearer token for the engine’s API under the key token (APIAccessTokenKey) and the API’s in-cluster base URL under the key url (APIAccessURLKey). It is for the company’s consumers (a control plane, a dashboard); the operator uses a token of its own, so revoking this one never locks the operator out. The token holds Crewlet’s admin grant, which takes in every app, so whoever holds it can rewrite the company document where the operator does not manage it, reveal every value in the engine’s secret store (the class’s platform model keys included: it is a deployment’s own token, not a person’s machine token, which Crewlet refuses a reveal), and invite or create the company’s people. Grant read on this Secret only to whoever may do that, by resourceNames: read on every Secret of the namespace also exposes | Optional: {} |
CompanyTopology
Section titled “CompanyTopology”CompanyTopology is how a company’s engine is laid out in pods: one data pod that holds the estate, serves the API and runs the background workers, and the seat pools, stateless pods that run the seats placed in them. Without seat pools every seat runs on the data pod.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
data DataTopology | data is the pods that hold the estate. | { replicas:1 } | MinProperties: 1 Optional: {} |
defaultSeatPool string | defaultSeatPool is the pool of every agent seat whose Seat names no spec.placement.pool: data, or the name of a Shared pool of seatPools. | data | MaxLength: 20 MinLength: 1 Pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ Optional: {} |
seatPools SeatPool array | seatPools are stateless pods that run seats. They need the class’s spec.seatPools.policy Allowed, and together run at most its maxPods pods. | MaxItems: 8 Optional: {} |
ConfigSettings
Section titled “ConfigSettings”ConfigSettings is how the operator manages a company’s document.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
managementPolicy ManagementPolicy | managementPolicy says who owns the document. Under Enforce the data pod’s crewlet.yaml sets Crewlet’s api.auth.company_writers to the operator’s own token, so the engine refuses every other credential a change to the document; under Observe and Seed it sets none, and Crewlet’s authority table decides who may. The engine reads crewlet.yaml only at start, so changing the policy to or from Enforce restarts the data pod. | Enforce | Enum: [Enforce Observe Seed] Optional: {} |
ConfigStatus
Section titled “ConfigStatus”ConfigStatus is the revision of the company document the engine runs.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
revisionID string | revisionID is the engine’s id of the last revision the operator saw run the rendered document: the one it applied, one the engine activated with the same content (a reload), or, under Observe, the one it found in sync. Under Seed it is the revision the document was seeded as. | MaxLength: 128 MinLength: 1 Optional: {} | |
epoch integer | epoch is the engine’s activation counter for that revision. The engine applies a revision asynchronously; it runs it once the applied epoch its /health reports has reached this. | Minimum: 0 Optional: {} | |
appliedHash string | appliedHash is the hash of the rendered document and of the values of the Secret keys it references, as last applied: a change to either is applied as a new revision, since the engine reads a rotated value only when a revision activates. The values enter it only as keyed fingerprints, so it reveals nothing about them. | MaxLength: 128 MinLength: 1 Optional: {} | |
appliedAt Time | appliedAt is when the operator last applied a revision. | Optional: {} | |
objects AppliedObjectCounts | objects counts the objects the revision was rendered from. | MinProperties: 1 Optional: {} | |
placement RevisionPlacement | placement is where the revision the engine runs pins its agent seats, read from the engine’s document under every management policy. The operator keeps a seat pool’s pods running while the running revision pins a seat to them, even after the pool or the seat’s placement is gone from the spec: a pod stopped while its seat is still pinned to it would leave the seat held by nobody, and a blocked document keeps the last good revision running. Once a revision that pins nothing to them runs, the pods are deleted. | MinProperties: 1 Optional: {} |
ConfluenceIntegration
Section titled “ConfluenceIntegration”ConfluenceIntegration turns Confluence on for a company: page changes wake the seats they concern, and the company may run Confluence as its knowledge base (the Company’s spec.knowledge.backend Confluence). It maps onto Crewlet’s integrations.confluence. Each seat’s Confluence identity is its own token, a credential of the MCPServer named atlassian in its Seat’s spec.mcp.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
url string | url is a Data Center instance’s or a Cloud site’s base URL. Unset with cloudID unset, the company’s Atlassian Integration discovers the site. Crewlet’s url. | MaxLength: 2048 MinLength: 1 Optional: {} | |
cloudID string | cloudID is an Atlassian Cloud site’s id; requests go through the API gateway of the Cloud siteURL is on: Atlassian Government Cloud’s, api.atlassian-us-gov-mod.com, for a site under atlassian-us-gov-mod.net, and api.atlassian.com otherwise. Crewlet’s cloud_id. | MaxLength: 64 MinLength: 1 Pattern: ^[A-Za-z0-9-]+$ Optional: {} | |
siteURL string | siteURL is the site’s address as a browser opens it, for the links the engine hands people; needed with cloudID, which is read through the gateway of this site’s Cloud. Unset is url. Crewlet’s site_url. | MaxLength: 2048 MinLength: 1 Optional: {} | |
email string | email is the account’s address, for Confluence Cloud’s basic authentication. Unset sends the token as a bearer token. Crewlet’s email. | MaxLength: 254 MinLength: 3 Pattern: ^[^@\s]+@[^@\s]+$ Optional: {} | |
tokenSecretRef SecretKeyReference | tokenSecretRef is the Secret key holding the API token (Cloud) or personal access token (Data Center) of the account a seat without a Confluence credential of its own searches as, which also reads the tool-skill pages. Crewlet’s token, a credential position. | Required: {} | |
webhookSecretRef SecretKeyReference | webhookSecretRef is the Secret key holding the secret a Data Center instance signs webhook deliveries with. Required for Data Center. Crewlet’s webhook_secret, a credential position. | Optional: {} | |
webhookTokenSecretRef SecretKeyReference | webhookTokenSecretRef is the Secret key holding the token a Confluence Cloud webhook carries in its delivery URL, Cloud signing nothing: at least 26 characters, random. Crewlet’s webhook_token, a credentialposition. | Optional: {} |
ContainerWebhookMode
Section titled “ContainerWebhookMode”Underlying type: string
ContainerWebhookMode is how webhooks are registered at GitHub: once on the
organization, or once per repository. It maps onto Crewlet’s org_webhook
(Auto is auto, Require is true, Never is false).
Validation:
- Enum: [Auto Require Never]
Appears in:
| Field | Description |
|---|---|
Auto | ContainerWebhookAuto uses one organization hook where the token may create one, and per-repository hooks otherwise. |
Require | ContainerWebhookRequire demands an organization hook. |
Never | ContainerWebhookNever always registers per-repository hooks. |
DataPodSettings
Section titled “DataPodSettings”DataPodSettings sizes the pods that hold a company’s estate. In v1alpha1 a company runs exactly one data pod, which also serves the API, runs the background workers and runs every seat placed in the pool data.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
allowedReplicas integer array | allowedReplicas is the set of data-pod counts a Company of this class may choose in spec.topology.data.replicas. v1alpha1 runs exactly one data pod, so the only value admitted is 1; 3 and 5, a highly available estate, are added when the operator can run them. | [1] | MaxItems: 1 MinItems: 1 items:Enum: [1] Optional: {} |
resources ResourceRequirements | resources are the compute resources of the engine container. | Optional: {} | |
storage DataStorage | storage is the data volume each data pod gets. | Required: {} | |
startupSeconds integer | startupSeconds is how long a data pod’s engine may take, from its start, to answer /health 200: the time it takes to recover what it holds on its volume (the store, the event stream, the replicated estate) and bring its broker up. Crewlet waits that recovery out rather than bounding it, because it grows with the data, so the startup probe is what bounds it: it allows at least this long from the container’s start, and less than ten seconds more. A boot that runs past it is restarted and begins its recovery again, so err long: a window that is too long costs nothing on a healthy boot, only the time to restart one that hung. It is at least every bound Crewlet puts on a data pod’s boot, laid end to end, which a window may not cut short: 1676 seconds, or 1816 with objects.backend S3, whose bucket every boot probes. Those are its waits for its own broker and store (provisioning the event stream, the coordination buckets, the object store and the state logs, two minutes a window on the broker of one member a data pod runs, and the requests around them), never for a peer or a seat pod. A few of them grow with what the company holds and are left to the recovery’s share, as the recovery is: a listing of its secrets, at up to 5 s a secret; moving a secret an offline crewlet secrets set left on the node, 10 s each;the claim of each batch of a seat pod’s events a crash left unsettled, 15 s a batch; and the restore of each CLI’s credential bundle, 10 s each. Unset derives it from the data volume: that floor plus six seconds per GiB of the volume. That is four times the second and a half per GiB Crewlet measured recovering after a crash on a fast local disk, for volumes that are network-attached; set this for disks slower than that. Nothing the company configures counts: the engine answers /health once it has recovered, while the company’s tool servers start. Changing it changes the data pods’ template, which restarts them. | Maximum: 86400 Minimum: 1676 Optional: {} | |
terminationGracePeriodSeconds integer | terminationGracePeriodSeconds is how long a data pod may take to stop. The engine finishes running turns before it exits and puts no bound on that itself, so the default is five minutes, which covers a long turn, rather than the Kubernetes default of thirty seconds, which does not. | 300 | Maximum: 3600 Minimum: 30 Optional: {} |
DataStorage
Section titled “DataStorage”DataStorage is the volume each data pod keeps the company’s estate on.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
storageClassName string | storageClassName is the StorageClass of the data volumes. Unset uses the cluster’s default class. | MaxLength: 253 MinLength: 1 Optional: {} | |
size Quantity | size is the capacity requested for each data volume. It holds the store, the event stream and the store’s cache. There is no default: how much a tenant may keep is a platform decision. Three quarters of it is the engine’s event stream, Crewlet’s stream.store_max_bytes: the stream reserves what a node keeps there up front, and a fresh node refuses to boot on a share that cannot hold it (Crewlet’s engine.BrokerFloor, and its deployment guide’s “minimum room for a fresh node”). Its seven state logs’ ceilings at their smallest come to 6979321856 bytes, so a volume must be at least 9Gi, whose share of 6.75Gi holds them. With objects.backend NATS, the default, the object store’s bucket reserves a quarter of the share beside them, 9305762474 bytes in all, so such a class must give at least 12Gi, whose share is 9Gi. That is the least that boots: the mailboxes and coordination buckets grow into what is left, so give a company that runs for long more. The stream’s ceiling is 64Ti (config.StoreMaxBytesCeiling, a guard against a unit mistake), so a volume larger than about 85Ti gives the stream 64Ti and the rest to the store and its snapshots. It applies to the data volumes of companies created after it is set. An existing company’s volumes keep the size they were created with: they are claimed through the StatefulSet’s volume claim templates, which Kubernetes does not let change, and growing a volume is a decision about one company’s storage class and data, not the class’s. Its owner expands the company’s claim instead, and once the expansion lands the operator sizes the stream from what the claim then has. | Required: {} |
DataTopology
Section titled “DataTopology”DataTopology is the pods that hold a company’s estate.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
replicas integer | replicas is the number of data pods. It must be one of the class’s spec.data.allowedReplicas. v1alpha1 runs exactly one data pod, so 1 is the only value admitted. A highly available estate of 3 or 5 is a later addition, and it comes with a rule that the count cannot change once set, because the event stream’s replication is fixed when the estate is created: admitting 3 or 5 before the operator can run them would leave Companies that could never be corrected. | 1 | Enum: [1] Minimum: 1 Optional: {} |
DataTopologyStatus
Section titled “DataTopologyStatus”DataTopologyStatus is the state of a company’s data pods.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
replicas integer | replicas is the number of data pods. | Minimum: 0 Optional: {} | |
readyReplicas integer | readyReplicas is the number of data pods that are ready. | Minimum: 0 Optional: {} | |
updatedReplicas integer | updatedReplicas is the number of data pods that run the current pod template. | Minimum: 0 Optional: {} |
DatadogIntegration
Section titled “DatadogIntegration”DatadogIntegration turns Datadog on for a company: a firing monitor wakes the seat its tags name. It maps onto Crewlet’s integrations.datadog. The engine registers the webhook at Datadog itself and creates a service account for each agent seat whose credentials for the MCPServer named datadog name a provisioned application key, so the Integration’s provisioning is Engine.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
webhookTokenSecretRef SecretKeyReference | webhookTokenSecretRef is the Secret key holding the token every delivery carries in its X-Crewlet-Token header: at least 26 characters, random. Datadog signs nothing, so this token is the whole of the check. Crewlet’s webhook_token, a credential position. | Required: {} | |
routeTo DatadogRouteTo | routeTo is where an alert goes whose monitor names no seat. Crewlet’s route_to. | MinProperties: 1 Required: {} | |
site DatadogSite | site is the region the organization, and so its keys, are in. Crewlet’s provisioning.site. | Enum: [US1 US3 US5 EU1 AP1 AP2 US1FED] Required: {} | |
apiKeySecretRef SecretKeyReference | apiKeySecretRef is the Secret key holding an API key of the organization, which says which organization a call is for. Crewlet’s provisioning.api_key, a credential position. | Required: {} | |
appKeySecretRef SecretKeyReference | appKeySecretRef is the Secret key holding an application key, which says which user acts: one allowed to manage webhooks and service accounts. Crewlet’s provisioning.app_key, a credential position. | Required: {} | |
role string | role is the Datadog role each seat’s service account is created with, by its name. Unset takes Crewlet’s default, Datadog Read Only Role. Crewlet’s provisioning.role. | MaxLength: 256 MinLength: 1 Optional: {} | |
emailDomain string | emailDomain is the domain the service accounts’ addresses are built under; Datadog requires an address and never writes to it. Unset takes Crewlet’s default, agents.crewlet.invalid. Crewlet’s provisioning.email_domain. | MaxLength: 253 MinLength: 1 Pattern: ^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$ Optional: {} | |
webhookName string | webhookName is the name of the webhook the engine keeps at Datadog, and so the handle monitors write: @webhook- Crewlet’s webhook_name. | MaxLength: 128 MinLength: 1 Pattern: ^[^ @,]+$ Optional: {} | |
handleTag string | handleTag is the monitor tag key whose value names the seat an alert wakes, such as crewlet:sre-lead. Unset is crewlet. Crewlet’s handle_tag. | MaxLength: 128 MinLength: 1 Pattern: ^[a-z][a-z0-9_./-]*$ Optional: {} |
DatadogRouteTo
Section titled “DatadogRouteTo”DatadogRouteTo is where an alert goes whose monitor names no seat.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
seatRef LocalObjectReference | seatRef names the agent Seat, in this namespace, the alert wakes. Crewlet’s route_to, as the seat’s handle. | Optional: {} | |
dismiss boolean | dismiss wakes nobody: only monitors that name a seat reach an agent, and the rest stay with whatever Datadog already does about them. Crewlet’s route_to: none. | Optional: {} |
DatadogSite
Section titled “DatadogSite”Underlying type: string
DatadogSite is the Datadog region a company’s organization is in. It maps onto Crewlet’s provisioning.site, the region’s host name (US1 is datadoghq.com, US3 us3.datadoghq.com, US5 us5.datadoghq.com, EU1 datadoghq.eu, AP1 ap1.datadoghq.com, AP2 ap2.datadoghq.com, US1FED ddog-gov.com).
Validation:
- Enum: [US1 US3 US5 EU1 AP1 AP2 US1FED]
Appears in:
| Field | Description |
|---|---|
US1 | |
US3 | |
US5 | |
EU1 | |
AP1 | |
AP2 | |
US1FED |
DeletionPolicy
Section titled “DeletionPolicy”Underlying type: string
DeletionPolicy is what happens to a company’s data volumes when the Company is deleted.
Validation:
- Enum: [Retain Delete]
Appears in:
| Field | Description |
|---|---|
Retain | DeletionPolicyRetain keeps the data volumes and the keyring Secret again with the same name and namespace finds both and its estate again. |
Delete | DeletionPolicyDelete deletes them with the Company. |
E2BSandbox
Section titled “E2BSandbox”E2BSandbox is the remote sandbox service seats run code in. Each field maps onto the same-named field of Crewlet’s providers.sandbox.e2b.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
apiKeySecretRef SecretKeyReference | apiKeySecretRef is the Secret key holding the service’s API key. Crewlet’s api_key, a credential position. | Required: {} | |
domain string | domain points at a self-hosted cluster of the service. Unset is the vendor’s cloud. | MaxLength: 253 MinLength: 1 Optional: {} | |
template string | template is the sandbox template, which also fixes each sandbox’s CPU, memory and disk. Unset, each run gets the vendor’s prebuilt template for its coding agent’s CLI (claude or opencode); a template set here is used for every run, so it must carry the CLI of every coding agent and Agent-mode CLIAgent provider the company runs. For OpenCode that is OpenCode 2, the @opencode/cli package (opencode —version prints opencode v2.…): Crewlet’s OpenCode runner ends a run at once in a box with OpenCode 1.x (npm’s opencode-ai), and E2B does not say which release its prebuilt opencode template carries, so a company whose OpenCode runs end that way sets template to one built with @opencode/cli. | MaxLength: 253 MinLength: 1 Optional: {} |
EmbeddingProviderType
Section titled “EmbeddingProviderType”Underlying type: string
EmbeddingProviderType is which embeddings API a company uses. It maps onto
Crewlet’s providers.embeddings.type (OpenAI is openai, OpenAICompatible
is openai-compatible).
Validation:
- Enum: [OpenAI OpenAICompatible]
Appears in:
| Field | Description |
|---|---|
OpenAI | EmbeddingProviderOpenAI is OpenAI’s embeddings API. |
OpenAICompatible | EmbeddingProviderOpenAICompatible is any endpoint that speaks it. |
EmbeddingSettings
Section titled “EmbeddingSettings”EmbeddingSettings is the provider a company computes vectors with, for semantic knowledge search and for recall of a seat’s memory. Each field maps onto the same-named field of Crewlet’s providers.embeddings.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
type EmbeddingProviderType | type is which embeddings API the provider speaks. | OpenAI | Enum: [OpenAI OpenAICompatible] Optional: {} |
model string | model is the embedding model id. Crewlet’s model. Crewlet trims it ofwhite space and refuses an embeddings provider with nothing left, as naming no model. | MaxLength: 256 MinLength: 1 Required: {} | |
apiKeySecretRef SecretKeyReference | apiKeySecretRef is the Secret key holding the API key. Crewlet’sapi_key, a credential position. Required for type OpenAI: Crewletreads OPENAI_API_KEY from the environment when it is unset, and the engine’s environment never carries one (see spec.runtime.env). An OpenAICompatible endpoint that needs no key may omit it. | Optional: {} | |
baseURL string | baseURL is the endpoint of an OpenAI-compatible service. Crewlet’sbase_url. | MaxLength: 2048 MinLength: 1 Optional: {} | |
dimensions integer | dimensions is the vector width. Unset takes the model’s own width, which Crewlet knows for the models it names; any other model needs it stated, and it must match what the model produces. | Maximum: 4096 Minimum: 64 Optional: {} | |
maxInputTokens integer | maxInputTokens is the most tokens one input may hold. Unset takes the model’s documented window; it may only lower it. | Minimum: 1 Optional: {} | |
maxBatchInputs integer | maxBatchInputs is the most inputs one request may carry. Unset takes the model’s documented limit; it may only lower it. | Minimum: 1 Optional: {} | |
maxBatchTokens integer | maxBatchTokens is the most tokens one request may carry, summed over its inputs. Unset takes the model’s documented limit; it may only lower it. | Minimum: 1 Optional: {} |
EngineClass
Section titled “EngineClass”EngineClass is a platform’s defaults and guard rails for running Crewlet engines: the image, the size of the data pods, how companies are exposed, and limits. A Company names one in spec.engineClassName; a platform that hosts many tenants usually writes one class for each service tier it offers them.
Anyone who may write a Company may name any class; a class admits the namespaces its spec.allowedNamespaces selects, and no others.
| Field | Description | Default | Validation |
|---|---|---|---|
apiVersion string | crewlet.ai/v1alpha1 | ||
kind string | EngineClass | ||
metadata ObjectMeta | Refer to Kubernetes API documentation for fields of metadata. | Optional: {} | |
spec EngineClassSpec | spec is the class’s desired state. | Required: {} | |
status EngineClassStatus | status is the class’s observed state. | MinProperties: 1 Optional: {} |
EngineClassSpec
Section titled “EngineClassSpec”EngineClassSpec is the defaults and guard rails a platform sets once for every Company that names the class, the way a StorageClass does for volumes. The data volume’s floor and the data pods’ startup window follow where the class keeps files (see DataStorage.size and DataPodSettings.startupSeconds): a company’s object store cannot move under them, since Crewlet refuses to start a node that names another store than the one it recorded, so the backend a volume and a window were sized for is the one it runs with.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
allowedNamespaces LabelSelector | allowedNamespaces selects, by their labels, the namespaces whose Companies may run with this class, as a Gateway’s allowedRoutes.namespaces.selector does; a Company in any other namespace is not accepted (Accepted=False, ClassNotAllowed). Unset, or an empty selector, admits every namespace. Running with a class is a privilege, and any subject that may write a Company may name any class: the class carries the platform’s Secrets it references (platform model keys, telemetry headers, env values) into each of its companies’ namespaces and engines, its workload identity onto the engine ServiceAccount, and its scheduling onto the platform’s nodes. A class with any of those should name the namespaces it is for. To select namespaces by name, match the label kubernetes.io/metadata.name, which the API server sets on every namespace. | Optional: {} | |
engine EngineSettings | engine is the engine image. | Required: {} | |
data DataPodSettings | data sizes the pods that hold each company’s estate. | Required: {} | |
seatPools SeatPoolSettings | seatPools is whether each company may run seats on stateless pods of its own, and how many. | { policy:Forbidden } | MinProperties: 1 Optional: {} |
stream StreamSettings | stream is how each company’s event stream runs. | { mode:Embedded } | MinProperties: 1 Optional: {} |
objects ObjectSettings | objects is where each company’s files are kept. | { backend:NATS } | MinProperties: 1 Optional: {} |
exposure ExposureSettings | exposure is how each company is reached from outside its namespace. | { api:map[mode:ClusterInternal] artifacts:map[mode:None] webhooks:map[mode:None] } | MinProperties: 1 Optional: {} |
networkPolicy NetworkPolicySettings | networkPolicy is the NetworkPolicy the operator puts around each company’s engine pods. | { mode:Isolated } | MinProperties: 1 Optional: {} |
podTemplate EnginePodTemplate | podTemplate is what is added to every engine pod. | MinProperties: 1 Optional: {} | |
serviceAccount EngineServiceAccount | serviceAccount is what is added to each company’s engine ServiceAccount. | MinProperties: 1 Optional: {} | |
service EngineService | service is what is added to each company’s engine Service, which the class’s routes send to. | MinProperties: 1 Optional: {} | |
platformLLMProviders PlatformLLMProvider array | platformLLMProviders are model providers the platform offers to companies that opt in. | MaxItems: 16 Optional: {} | |
limits EngineLimits | limits caps what a company may declare. | MinProperties: 1 Optional: {} | |
telemetry TelemetrySettings | telemetry sends the engine’s traces to a collector. Unset exports nothing. | Optional: {} | |
retention RetentionSettings | retention is who answers for backups. | Optional: {} | |
signIn SignInSettings | signIn is how people prove who they are when they sign in to each company’s dashboard. Unset, everyone gives a second factor, as Crewlet requires by default. | MinProperties: 1 Optional: {} |
EngineClassStatus
Section titled “EngineClassStatus”EngineClassStatus is what the operator observed about an EngineClass.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
conditions Condition array | conditions has Accepted: whether the objects the class names in other namespaces exist, which its schema cannot check. It is False with SecretNotFound when a Secret or key the class references does not exist, GatewayAPINotInstalled when it routes through Gateways on a cluster without the Gateway API, and GatewayNotFound when a Gateway a route names with its namespace does not exist. Companies of a class that is not accepted still run, and report what the problem does to them on their own conditions. | MaxItems: 8 Optional: {} | |
observedGeneration integer | observedGeneration is the metadata.generation this status describes. | Minimum: 1 Optional: {} |
EngineConfigEntry
Section titled “EngineConfigEntry”EngineConfigEntry is one top-level key of the company document that spec.engineConfig passes through, and its value.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name is the key, as Crewlet spells it, such as turn_engine. | MaxLength: 63 MinLength: 1 Pattern: ^[a-z][a-z0-9_]*$ Required: {} | |
value EngineConfigValue | value is the key’s value: an object, a list, a string, a number or a boolean, kept as written. | Type: Required: {} |
EngineConfigValue
Section titled “EngineConfigValue”EngineConfigValue is any JSON value, kept byte for byte as it was written.
Validation:
- Type:
Appears in:
EngineLimits
Section titled “EngineLimits”EngineLimits caps what a Company of a class may declare. The operator refuses to apply a company that exceeds a limit and reports it on the Company. A control plane should refuse such a request before it writes the Company; this is the cluster’s defence in depth.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
maxSeats integer | maxSeats is the most Seats a Company may have. Unset is unlimited. | Minimum: 0 Optional: {} | |
maxMCPServers integer | maxMCPServers is the most MCPServers a Company may have. Unset is unlimited. | Minimum: 0 Optional: {} |
EnginePodMetadata
Section titled “EnginePodMetadata”EnginePodMetadata is metadata added to every engine pod.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
labels object (keys:string, values:string) | labels are added to every engine pod. | MaxProperties: 32 Optional: {} | |
annotations object (keys:string, values:string) | annotations are added to every engine pod. | MaxProperties: 32 Optional: {} |
EnginePodSpec
Section titled “EnginePodSpec”EnginePodSpec is the part of a pod’s spec a class may set on engine pods. It is a closed list rather than a whole PodSpec: the operator owns the containers, volumes, probes and security context, because the engine’s data safety depends on them.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
nodeSelector object (keys:string, values:string) | nodeSelector constrains engine pods to nodes with these labels. | MaxProperties: 32 Optional: {} | |
tolerations Toleration array | tolerations let engine pods run on tainted nodes. | MaxItems: 32 Optional: {} | |
affinity Affinity | affinity is the engine pods’ scheduling affinity. | Optional: {} | |
topologySpreadConstraints TopologySpreadConstraint array | topologySpreadConstraints spread engine pods across topology domains. | MaxItems: 8 Optional: {} | |
runtimeClassName string | runtimeClassName is the RuntimeClass engine pods run with, for example a sandboxed runtime such as gVisor. | MaxLength: 253 MinLength: 1 Optional: {} | |
priorityClassName string | priorityClassName is the PriorityClass of engine pods. | MaxLength: 253 MinLength: 1 Optional: {} | |
env ClassEnvVar array | env adds environment variables to the engine container of every Company of the class: platform wiring that is the same for all of them, such as the address of the platform’s own API. Every value, one from a Secret included, reaches every tenant of the class: code the tenant runs in the engine’s pod can read its environment. They are the engine’s environment, not that of the processes it starts: a Stdio tool server is handed only the part Crewlet’s allowlist names, such as PATH and the TLS and proxy variables, a coding CLI that part and the variables its Crewlet profile passes through, such as GeminiCLI’s GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION, and a sandbox run none of it. So a variable a tool server reads goes in its MCPServer’s env (docs/guides/tool-servers.md), and any other a coding CLI reads in its LLMProvider’s spec.cli.env. A Company’s spec.runtime.env is merged over this env by name. The same names are refused as there: those starting with CREWLET_ or OTEL_, and ANTHROPIC_API_KEY and OPENAI_API_KEY. | MaxItems: 32 Optional: {} |
EnginePodTemplate
Section titled “EnginePodTemplate”EnginePodTemplate is what a class adds to every engine pod.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
metadata EnginePodMetadata | Refer to Kubernetes API documentation for fields of metadata. | MinProperties: 1 Optional: {} | |
spec EnginePodSpec | spec is merged into every engine pod’s spec. | MinProperties: 1 Optional: {} |
EngineService
Section titled “EngineService”EngineService is what a class adds to the Service
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
annotations object (keys:string, values:string) | annotations are added to the Service, for a load balancer controller that reads a backend’s settings from it. On GKE an Ingress takes its health check from cloud.google.com/backend-config, naming a BackendConfig in each company’s namespace: point its check at port 8080, path /ready, since the public port the webhooks’ route sends to answers 404 on every path it does not serve, / included. | MaxProperties: 16 Optional: {} |
EngineServiceAccount
Section titled “EngineServiceAccount”EngineServiceAccount is what a class adds to the ServiceAccount the operator creates for each Company’s engine pods.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
annotations object (keys:string, values:string) | annotations are added to the ServiceAccount, for a workload identity that is bound through one: eks.amazonaws.com/role-arn for IRSA, iam.gke.io/gcp-service-account for GKE Workload Identity. That is how the engine reaches an S3 bucket when its Company names no spec.objects.credentialsSecretRef. The same annotations go on every company’s ServiceAccount, so the identity is every tenant’s: scope it per tenant (a role per company, or a session policy limited to the company’s prefix), or give each Company keys of its own instead. | MaxProperties: 16 Optional: {} |
EngineSettings
Section titled “EngineSettings”EngineSettings is the engine image a class runs.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
image string | image is the Crewlet engine image, by tag or by digest, for example registry.example.com/crewlet:v1.2.3. There is no default: the platform decides which build its tenants run. A Company’s spec.runtime.version replaces the tag, so an image pinned by digest cannot be combined with allowVersionOverride. | MaxLength: 512 MinLength: 1 Required: {} | |
imagePullPolicy PullPolicy | imagePullPolicy is the pull policy of the engine container. Unset takes the Kubernetes default for the image reference. | Enum: [Always IfNotPresent Never] Optional: {} | |
imagePullSecrets LocalObjectReference array | imagePullSecrets name Secrets in each Company’s namespace that pull the image. They are referenced, not copied: the platform puts them into the tenant namespaces it creates. | MaxItems: 8 Optional: {} | |
allowVersionOverride boolean | allowVersionOverride lets a Company of this class choose its own engine version with spec.runtime.version. Off by default: the platform usually decides which version a class’s tenants run. | Optional: {} |
EngineStatus
Section titled “EngineStatus”EngineStatus is what runs a company.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
image string | image is the engine image the data pods last ran on, recorded once every data pod ran it and was ready. A rollout that has not finished leaves the previous image here. | MaxLength: 512 MinLength: 1 Optional: {} | |
version string | version is the tag of that image, such as v1.2.3; unset for an image pinned by digest alone. The engine migrates its data forward only, so the operator refuses to roll the data pods to an image whose tag is an older semantic version than this one (RuntimeReady=False, DowngradeRefused). The operator also records it on each data volume claim (the annotation crewlet.ai/engine-version), which keeps the floor when this status is lost. A version that never became ready is never recorded, so a rollout that failed can still be taken back. | MaxLength: 128 MinLength: 1 Optional: {} |
EnvVar
Section titled “EnvVar”EnvVar is an environment variable set on the engine’s pods. Unlike SecretEnvVar it may carry a literal value, because it is not a Crewlet credential position but platform wiring (a feature flag, an endpoint); a sensitive value is referenced from a Secret with valueFrom, which Kubernetes resolves when it starts the container, so the value never appears in the pod template.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name is the variable’s name. | MaxLength: 128 MinLength: 1 Pattern: ^[A-Za-z_][A-Za-z0-9_]*$ Required: {} | |
value string | value is the variable’s literal value. An empty string is a valid value, which is why the field is a pointer. | MaxLength: 4096 Optional: {} | |
valueFrom SecretValueSource | valueFrom reads the value from a Secret key in the Company’s namespace. | Optional: {} |
ExposureSettings
Section titled “ExposureSettings”ExposureSettings is how a class’s companies are reached.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
webhooks WebhookExposure | webhooks is how vendors’ webhooks reach the engine. | { mode:None } | MinProperties: 1 Optional: {} |
api APIExposure | api is how the engine’s API is reached. | { mode:ClusterInternal } | MinProperties: 1 Optional: {} |
artifacts ArtifactExposure | artifacts is how browsers reach the artifact origin. | { mode:None } | MinProperties: 1 Optional: {} |
trustedProxies string array | trustedProxies are the address blocks of what forwards requests to the engine: the Gateway’s proxies or the Ingress controller of the class’s routes, and whatever balances in front of them. Crewlet takes a request’s client address from its X-Forwarded-For header only when the request arrives from one of these, and otherwise uses the address it arrives from, which behind a proxy is the proxy’s for every caller: the sign-in throttle then counts everyone’s attempts at one login together, so a stranger guessing at a person’s login holds up that person’s own sign-in, and the audit trail names the proxy. Each is a canonical IPv4 or IPv6 CIDR narrower than the whole address space; a single host is a /32 or /128. Unset, no forwarded header is believed. Crewlet’s api.trusted_proxies. | MaxItems: 16 MinItems: 1 items:MaxLength: 43 Optional: {} |
ExternalExposure
Section titled “ExternalExposure”ExternalExposure is where the forwarder of a class’s webhooks runs, when something outside the operator forwards them (webhooks.mode External).
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
forwarders NetworkPolicyPeer array | forwarders are the pods that forward webhooks to the engine’s public port: a tunnel’s or a relay’s pods in the cluster. They are required under networkPolicy Isolated, which admits them to that port and to nothing else of the engine, and refused under any other mode, which has no policy to admit them to. A forwarder outside the pod network (a load balancer of your own that sends traffic from the nodes or from outside the cluster) cannot be admitted by namespace: isolate those engines with your CNI’s own policy and networkPolicy.mode None. | MaxItems: 16 MinItems: 1 Optional: {} |
GatewayExposure
Section titled “GatewayExposure”GatewayExposure attaches a company’s routes to Gateways.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
parentRefs GatewayParentReference array | parentRefs are the Gateways the HTTPRoute attaches to. | MaxItems: 8 MinItems: 1 Required: {} | |
proxyNamespaces string array | proxyNamespaces are the namespaces the pods that carry the Gateways’ traffic run in. Under networkPolicy Isolated they are admitted to the one port of the engine the route reaches: the public listener for the webhooks’ route, the API port for the API’s, the artifact listener for the artifacts’. Unset is the namespaces of parentRefs, which is right for implementations that run a proxy beside each Gateway (Istio, for example); implementations with a shared data plane run it elsewhere (Envoy Gateway in envoy-gateway-system, for example) and need it named here. | MaxItems: 8 MinItems: 1 items:MaxLength: 63 items:MinLength: 1 items:Pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ Optional: {} |
GatewayParentReference
Section titled “GatewayParentReference”GatewayParentReference names a Gateway API Gateway (or one listener of it) that the operator attaches a company’s HTTPRoute to.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
namespace string | namespace is the Gateway’s namespace. Unset is the Company’s own namespace. | MaxLength: 63 MinLength: 1 Optional: {} | |
name string | name is the Gateway’s name. | MaxLength: 253 MinLength: 1 Required: {} | |
sectionName string | sectionName is the name of one listener of the Gateway. Unset attaches to every listener that accepts the route. | MaxLength: 253 MinLength: 1 Optional: {} |
GitHubAccessTier
Section titled “GitHubAccessTier”Underlying type: string
GitHubAccessTier is how much a seat may do in a repository. It maps onto
Crewlet’s role integrations.github.tier (ReadOnly is read_only, Review is
review, FullAccess is full_access).
Validation:
- Enum: [ReadOnly Review FullAccess]
Appears in:
| Field | Description |
|---|---|
ReadOnly | |
Review | |
FullAccess |
GitHubApp
Section titled “GitHubApp”GitHubApp is the GitHub App a seat acts as. An app carries exactly one bot identity, so every agent seat that works on GitHub has its own.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
id integer | id is the app’s numeric id. Crewlet’s app_id. | Minimum: 1 Required: {} | |
slug string | slug is the app’s slug; the bot’s login, and so how the seat is mentioned, derives from it. Crewlet’s app_slug. | MaxLength: 128 MinLength: 1 Pattern: ^[a-z0-9][a-z0-9-]*$ Required: {} | |
installationID integer | installationID is the app’s installation on the organization. Unset while the app is created but not yet installed. Crewlet’s installation_id. | Minimum: 1 Optional: {} | |
credentialsSecretRef SecretReference | credentialsSecretRef is a Secret holding the app’s credentials under the keys privateKey (the app’s PEM key) and webhookSecret (which verifies the app’s own webhook deliveries). Crewlet’s private_keyand webhook_secret, both credential positions. | Required: {} |
GitHubIntegration
Section titled “GitHubIntegration”GitHubIntegration turns GitHub on for a company: webhooks from github.com or a GitHub Enterprise Server wake the seats they concern. It maps onto Crewlet’s integrations.github. Each agent seat’s own GitHub App is in its Seat’s spec.integrations.github; the GitHub tools are an MCPServer.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
url string | url is the base URL of a GitHub Enterprise Server, such as https://github.example.com. Unset is github.com. Crewlet’s url. | MaxLength: 2048 MinLength: 1 Optional: {} | |
webhookSecretRef SecretKeyReference | webhookSecretRef is the Secret key holding the secret that verifies webhooks delivered to the company-wide route. Crewlet’s webhook_secret, a credential position. | Required: {} | |
tokenSecretRef SecretKeyReference | tokenSecretRef is the Secret key holding an organization token with the admin:org_hook scope, which the engine registers the company’s webhooks with. Unset registers none. Crewlet’s token, a credentialposition. | Optional: {} | |
provisioning GitHubProvisioning | provisioning is where the webhooks are registered. It requires tokenSecretRef, without which the engine registers nothing. | MinProperties: 1 Optional: {} |
GitHubProvisioning
Section titled “GitHubProvisioning”GitHubProvisioning is where the engine registers the company’s webhooks at GitHub. It maps onto Crewlet’s integrations.github.provisioning. The engine registers them with the organization token (tokenSecretRef); without one it registers nothing and each seat’s own app delivers its own webhooks.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
org string | org is the GitHub organization holding the repositories. Crewlet’sorg. | MaxLength: 39 MinLength: 1 Pattern: ^[A-Za-z0-9-]+$ Optional: {} | |
repos string array | repos are repositories, as owner/name, to register a webhook on one by one. Crewlet’s repos. | MaxItems: 128 items:MaxLength: 201 items:Pattern: ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ Optional: {} | |
orgWebhook ContainerWebhookMode | orgWebhook is whether one organization hook replaces the per-repository ones. Unset is Auto. Crewlet’s org_webhook. | Enum: [Auto Require Never] Optional: {} |
GitHubSeatIntegration
Section titled “GitHubSeatIntegration”GitHubSeatIntegration is a seat’s identity on GitHub. It maps onto Crewlet’s role integrations.github and needs the company’s GitHub Integration.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
tier GitHubAccessTier | tier is how much the seat may do in a repository. Unset is ReadOnly. Crewlet’s tier. | Enum: [ReadOnly Review FullAccess] Optional: {} | |
repos string array | repos are the repositories the seat works in, as owner/name. Unset is every repository the app’s installation covers. Crewlet’s repos. | MaxItems: 64 items:MaxLength: 201 items:Pattern: ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ Optional: {} | |
app GitHubApp | app is the GitHub App the seat acts as. | Optional: {} |
GitHubSeatStatus
Section titled “GitHubSeatStatus”GitHubSeatStatus is the GitHub side of a seat, as the operator computed it.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
webhookURL string | webhookURL is the URL the seat’s GitHub App must deliver webhooks to, is set whenever the Company has a GitHub Integration and a public base URL, before the seat’s app exists, and it never changes for a seat. | MaxLength: 2048 MinLength: 1 Optional: {} |
GitLabAccessLevel
Section titled “GitLabAccessLevel”Underlying type: string
GitLabAccessLevel is the membership level the engine gives a seat’s GitLab
service account. It maps onto Crewlet’s access_level (Developer is
developer, Maintainer is maintainer).
Validation:
- Enum: [Developer Maintainer]
Appears in:
| Field | Description |
|---|---|
Developer | GitLabDeveloper can push branches and open merge requests. |
Maintainer | GitLabMaintainer can also merge to protected branches. |
GitLabAccountOwner
Section titled “GitLabAccountOwner”Underlying type: string
GitLabAccountOwner is where the engine creates the seats’ GitLab service
accounts. It maps onto Crewlet’s provisioning mode (Group is group,
Instance is instance).
Validation:
- Enum: [Group Instance]
Appears in:
| Field | Description |
|---|---|
Group | GitLabAccountOwnerGroup creates them under the group, which is all GitLab.com offers. |
Instance | GitLabAccountOwnerInstance creates them on a self-managed instance itself, with an instance administrator’s token. |
GitLabEngineProvisioning
Section titled “GitLabEngineProvisioning”GitLabEngineProvisioning is how the engine provisions the seats’ GitLab accounts under provisioning Engine. It maps onto Crewlet’s integrations.gitlab.provisioning: for each agent seat whose credentials for the MCPServer named gitlab name a provisioned value, the engine creates a service account, adds it to the group and the projects, mints a token into that value, and registers the webhook.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
group string | group is the top-level group, by its path, the service accounts join and the webhook is registered on. Crewlet’s group. | MaxLength: 255 MinLength: 1 Pattern: ^[A-Za-z0-9_.][A-Za-z0-9_./-]*$ Required: {} | |
adminTokenSecretRef SecretKeyReference | adminTokenSecretRef is the Secret key holding a personal access token with the api scope of an Owner of the group (of an instance administrator, for accountOwner Instance), which creates and removes the service accounts. Crewlet’s admin_token, a credential position. | Required: {} | |
accountOwner GitLabAccountOwner | accountOwner is where the service accounts are created. Unset is Group. Crewlet’s mode. | Enum: [Group Instance] Optional: {} | |
accessLevel GitLabAccessLevel | accessLevel is the membership level of every seat’s account. Unset takes Crewlet’s default, Developer. Crewlet’s access_level. | Enum: [Developer Maintainer] Optional: {} | |
accessLevels GitLabSeatAccess array | accessLevels override accessLevel for single seats. Crewlet’saccess_levels. | MaxItems: 64 Optional: {} | |
usernamePrefix string | usernamePrefix is put before each seat’s handle to form its account’s username, for a group shared with people. Crewlet’s username_prefix. | MaxLength: 32 MinLength: 1 Pattern: ^[A-Za-z0-9_.-]+$ Optional: {} | |
projects string array | projects are projects, by path, the accounts also join, and the ones the webhook is registered on one by one when no group hook is. Crewlet’s projects. | MaxItems: 128 items:MaxLength: 255 items:MinLength: 1 items:Pattern: ^[A-Za-z0-9_.][A-Za-z0-9_./-]*$ Optional: {} | |
groupWebhook ContainerWebhookMode | groupWebhook is whether one group hook replaces the per-project ones. Unset is Auto. Crewlet’s group_webhook. | Enum: [Auto Require Never] Optional: {} | |
tokenScopes string array | tokenScopes are the scopes minted on each seat’s token. Unset takes Crewlet’s default, api. Crewlet’s token_scopes. | MaxItems: 16 items:MaxLength: 64 items:MinLength: 1 items:Pattern: ^[a-z_]+$ Optional: {} |
GitLabIntegration
Section titled “GitLabIntegration”GitLabIntegration turns GitLab on for a company: webhooks from a GitLab instance wake the seats they concern. It maps onto Crewlet’s integrations.gitlab. Each seat’s GitLab token is a credential of the MCPServer named gitlab in its Seat’s spec.mcp, which is where Crewlet reads a seat’s GitLab identity from.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
url string | url is the instance’s base URL, such as https://gitlab.com. Crewlet’surl. | MaxLength: 2048 MinLength: 1 Required: {} | |
signingSecretRef SecretKeyReference | signingSecretRef is the Secret key holding the signing token every webhook delivery is verified against: whsec_ followed by the standard base64 of 32 bytes, the only form GitLab signs with (its “Generate signing token” button makes one). Crewlet’s signing_secret, acredential position. | Required: {} | |
tokenSecretRef SecretKeyReference | tokenSecretRef is the Secret key holding a personal access token with the read_api scope, which the engine reads an issue’s or merge request’s participants with, so that everyone in a thread hears its activity. Unset routes to the people a delivery names only. Crewlet’s token, a credential position. | Optional: {} | |
webhookName string | webhookName is the name of the hooks the engine registers, which is how it tells its own from others on the instance: two deployments watching one instance need two names. Unset is crewlet. Crewlet’s webhook_name. | MaxLength: 255 MinLength: 1 Optional: {} | |
engineProvisioning GitLabEngineProvisioning | engineProvisioning is how the engine creates the seats’ accounts. Required with provisioning Engine, and not allowed with External. | Optional: {} |
GitLabSeatAccess
Section titled “GitLabSeatAccess”GitLabSeatAccess overrides the access level of one seat’s service account.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name is the metadata.name of the Seat, in this namespace. Crewlet keys the override by the seat’s handle, which the operator renders. | MaxLength: 253 MinLength: 1 Required: {} | |
accessLevel GitLabAccessLevel | accessLevel is the seat’s membership level. | Enum: [Developer Maintainer] Required: {} |
IngressExposure
Section titled “IngressExposure”IngressExposure puts a company’s routes on an Ingress.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
className string | className is the IngressClass. Unset uses the cluster’s default class. | MaxLength: 253 MinLength: 1 Optional: {} | |
annotations object (keys:string, values:string) | annotations are added to the Ingress, for the controller that serves it or a certificate controller. | MaxProperties: 32 Optional: {} | |
tls IngressTLS | tls terminates TLS on the Ingress. Unset serves plain HTTP, which is right only behind something else that terminates TLS: vendors deliver webhooks over HTTPS only. | Optional: {} | |
controllerNamespaces string array | controllerNamespaces are the namespaces the Ingress controller’s pods run in. Under networkPolicy Isolated they are admitted to the one port of the engine the Ingress reaches (the public listener for the webhooks’ Ingress, the API port for the API’s, the artifact listener for the artifacts’), and they are required there: an Ingress does not say which pods serve it, and without them the policy would refuse every request the Ingress forwards. | MaxItems: 8 MinItems: 1 items:MaxLength: 63 items:MinLength: 1 items:Pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ Optional: {} |
IngressTLS
Section titled “IngressTLS”IngressTLS terminates TLS on a company’s Ingress.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
secretName string | secretName is the TLS Secret, in the Company’s namespace, the Ingress presents. It is a template like the hostname: {{namespace}}, {{name}} and {{uid}} are replaced. A certificate controller that issues certificates from Ingress annotations creates it; set those annotations under ingress.annotations. | MaxLength: 253 MinLength: 1 Required: {} |
Integration
Section titled “Integration”Integration connects a company to a vendor (Slack, GitHub, GitLab, Mattermost, Jira, Confluence, Datadog or an Atlassian organization): the company-wide settings, the credentials that verify the vendor’s webhooks, and, where the engine creates the seats’ accounts, the administrator credential it creates them with. Credentials that belong to one seat, such as its own Slack app or its GitLab token, are on the Seat.
| Field | Description | Default | Validation |
|---|---|---|---|
apiVersion string | crewlet.ai/v1alpha1 | ||
kind string | Integration | ||
metadata ObjectMeta | Refer to Kubernetes API documentation for fields of metadata. | Optional: {} | |
spec IntegrationSpec | spec is the integration’s desired state. | Required: {} | |
status IntegrationStatus | status is the integration’s observed state. | MinProperties: 1 Optional: {} |
IntegrationProvisioning
Section titled “IntegrationProvisioning”Underlying type: string
IntegrationProvisioning is who creates the seats’ accounts at a vendor, and so where their credentials come from.
Validation:
- Enum: [External Engine]
Appears in:
| Field | Description |
|---|---|
External | IntegrationProvisioningExternal leaves the seats’ accounts to someone outside the engine (a person, a platform): each seat’s credentials are Secrets its Seat references, and the engine is given no administrator credential, so it creates, changes and removes nothing at the vendor. |
Engine | IntegrationProvisioningEngine has the engine create each agent seat’s account with an administrator credential the Integration references, mint the account’s credential into the engine’s secret store, register the company’s webhooks, and heal all of it on a schedule. Seats name the minted credentials as provisioned values. |
IntegrationSpec
Section titled “IntegrationSpec”IntegrationSpec connects a company to one vendor. Exactly one vendor member is set; the Integration’s kind of vendor cannot change, and a company has at most one Integration per vendor (a second is reported as a conflict).
provisioning says who creates the seats’ accounts at the vendor. Under External (the default) someone else does, and every per-seat credential comes from a Secret its Seat references; the Integration then holds no administrator credential. Under Engine the engine creates them, from the administrator credential the vendor member references, and seats name the credentials it mints as provisioned values. The engine can create accounts at GitLab, Mattermost, Datadog and Atlassian; Datadog and Atlassian are always provisioned by the engine, and Slack, GitHub, Jira and Confluence never are (the engine mints no credential there).
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
companyRef CompanyReference | companyRef names the Company this integration belongs to. Immutable. | Required: {} | |
provisioning IntegrationProvisioning | provisioning is who creates the seats’ accounts at the vendor. Unset is External. | Enum: [External Engine] Optional: {} | |
slack SlackIntegration | slack connects Slack. | Optional: {} | |
github GitHubIntegration | github connects GitHub. | Optional: {} | |
gitlab GitLabIntegration | gitlab connects GitLab. | Optional: {} | |
mattermost MattermostIntegration | mattermost connects Mattermost. | Optional: {} | |
jira JiraIntegration | jira connects Jira. | Optional: {} | |
confluence ConfluenceIntegration | confluence connects Confluence. | Optional: {} | |
datadog DatadogIntegration | datadog connects Datadog. | Optional: {} | |
atlassian AtlassianIntegration | atlassian connects an Atlassian Cloud organization. | Optional: {} |
IntegrationStatus
Section titled “IntegrationStatus”IntegrationStatus is what the operator observed about an Integration.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
conditions Condition array | conditions are Accepted (the Company exists and has no other Integration for the vendor), ResolvedRefs (every Secret key exists), Applied (the integration is in the revision the engine runs) and Healthy (the engine’s own check of the vendor passes). | MaxItems: 8 Optional: {} | |
observedGeneration integer | observedGeneration is the metadata.generation this status describes. | Minimum: 1 Optional: {} | |
webhookURL string | webhookURL is the company-wide URL the vendor delivers webhooks to, when the company is exposed and the vendor has one: Confluence (a Data Center instance’s; Confluence Cloud delivers to Datadog. Slack, Mattermost and Atlassian have none; Slack’s and GitHub’s per-seat URLs are in each Seat’s status. | MaxLength: 2048 MinLength: 1 Optional: {} |
JiraIntegration
Section titled “JiraIntegration”JiraIntegration turns Jira on for a company: webhooks from a Jira site wake the seats they concern, and the company may run Jira as its tracker (the Company’s spec.tracker.backend Jira). It maps onto Crewlet’s integrations.jira. Each seat’s Jira identity is its own token, a credential of the MCPServer named atlassian (or jira) in its Seat’s spec.mcp.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
url string | url is a Data Center instance’s or a Cloud site’s base URL. Unset with cloudID unset, the company’s Atlassian Integration discovers the site. Crewlet’s url. | MaxLength: 2048 MinLength: 1 Optional: {} | |
cloudID string | cloudID is an Atlassian Cloud site’s id; requests go through the API gateway of the Cloud siteURL is on: Atlassian Government Cloud’s, api.atlassian-us-gov-mod.com, for a site under atlassian-us-gov-mod.net, and api.atlassian.com otherwise. Crewlet’s cloud_id. | MaxLength: 64 MinLength: 1 Pattern: ^[A-Za-z0-9-]+$ Optional: {} | |
siteURL string | siteURL is the site’s address as a browser opens it, for the links the engine hands people; needed with cloudID, whose gateway address opens nothing in a browser, and which is read through the gateway of this site’s Cloud. Unset is url. Crewlet’s site_url. | MaxLength: 2048 MinLength: 1 Optional: {} | |
email string | email is the account’s address, for Jira Cloud’s basic authentication. Unset sends the token as a bearer token, as a service account and a Data Center personal access token want. Crewlet’s email. | MaxLength: 254 MinLength: 3 Pattern: ^[^@\s]+@[^@\s]+$ Optional: {} | |
tokenSecretRef SecretKeyReference | tokenSecretRef is the Secret key holding the API token (Cloud) or personal access token (Data Center) of an administrator account. The engine reads an issue’s watchers with it, which no webhook carries, and registers the company’s webhook. Crewlet’s token, a credentialposition. | Required: {} | |
webhookSecretRef SecretKeyReference | webhookSecretRef is the Secret key holding the secret webhook deliveries are signed with. Required for a Data Center instance, whose route answers none without it; on Cloud, webhooks the engine registers are signed with it, and the Forge relay needs none. Crewlet’s webhook_secret, a credential position. | Optional: {} | |
webhookName string | webhookName is the name of the webhook the engine registers, which is how it tells its own from others on the site: two deployments watching one site need two names. Unset is crewlet. Crewlet’s webhook_name. | MaxLength: 255 MinLength: 1 Optional: {} |
KnowledgeBackend
Section titled “KnowledgeBackend”Underlying type: string
KnowledgeBackend is which knowledge base a company runs. It maps onto
Crewlet’s knowledge.backend (Native is native, Confluence is
confluence, None is none).
Validation:
- Enum: [Native Confluence None]
Appears in:
| Field | Description |
|---|---|
Native | KnowledgeNative is the engine’s own knowledge base. |
Confluence | KnowledgeConfluence is Confluence, connected by the company’s Confluence Integration. |
None | KnowledgeNone is a company with no knowledge base. |
KnowledgeSettings
Section titled “KnowledgeSettings”KnowledgeSettings is which knowledge base a company runs and how it is searched. It maps onto Crewlet’s knowledge block.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
backend KnowledgeBackend | backend is which knowledge base the company runs. | Native | Enum: [Native Confluence None] Optional: {} |
scope string array | scope narrows every knowledge search to these containers. Empty searches the whole company. Each is a container key, which Crewlet requires to be an upper-case letter followed by 1 to 9 upper-case letters or digits, such as PLAT. Crewlet’s scope. | MaxItems: 64 items:MaxLength: 10 items:MinLength: 2 items:Pattern: ^[A-Z][A-Z0-9]\{1,9\}$ Optional: {} | |
skillsContainer string | skillsContainer is the container holding tool-skill pages, a container key (see scope). Unset takes Crewlet’s default container; an empty string turns tool skills off. Crewlet’s skills_container. | MaxLength: 10 Optional: {} | |
rootSpace string | rootSpace is the container holding the company’s own pages, such as the root onboarding page, a container key (see scope). Unset takes Crewlet’s default. Crewlet’s root_space. | MaxLength: 10 MinLength: 2 Pattern: ^[A-Z][A-Z0-9]\{1,9\}$ Optional: {} | |
vectors boolean | vectors fuses semantic recall into knowledge and work search; false also stops embedding the corpus. Unset is on exactly when the company has an embeddings provider; true requires one (spec.embeddings). Crewlet’s vectors. | Optional: {} |
LLMCredentialCooldowns
Section titled “LLMCredentialCooldowns”LLMCredentialCooldowns is how long a key that failed is set aside before it
is tried again. It maps onto Crewlet’s cooldowns block.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
rateLimitSeconds integer | rateLimitSeconds is how long a key that hit a rate limit is set aside. Unset takes Crewlet’s default of 3600. | Maximum: 86400 Minimum: 60 Optional: {} | |
authSeconds integer | authSeconds is how long a key the provider refused is set aside. Unset takes Crewlet’s default of 300. | Maximum: 86400 Minimum: 60 Optional: {} |
LLMProvider
Section titled “LLMProvider”LLMProvider is a model provider a company’s seats can run on: one entry of Crewlet’s providers.llm, keyed by its name. The name default is refused: Crewlet runs a seat that names no chain on the provider keyed default when there is one, whatever the Company’s spec.llm.order says.
| Field | Description | Default | Validation |
|---|---|---|---|
apiVersion string | crewlet.ai/v1alpha1 | ||
kind string | LLMProvider | ||
metadata ObjectMeta | Refer to Kubernetes API documentation for fields of metadata. | Optional: {} | |
spec LLMProviderSpec | spec is the provider’s desired state. | Required: {} | |
status LLMProviderStatus | status is the provider’s observed state. | MinProperties: 1 Optional: {} |
LLMProviderKind
Section titled “LLMProviderKind”Underlying type: string
LLMProviderKind is the kind of model provider a reference names.
Validation:
- Enum: [LLMProvider PlatformLLMProvider]
Appears in:
| Field | Description |
|---|---|
LLMProvider | LLMProviderKindLLMProvider is an LLMProvider in the referring object’s namespace. |
PlatformLLMProvider | LLMProviderKindPlatform is an entry of the Company’s EngineClass spec.platformLLMProviders; the Company must set spec.llm.usePlatformProviders. |
LLMProviderReference
Section titled “LLMProviderReference”LLMProviderReference names a model provider: an LLMProvider in the referring object’s namespace, or a provider the EngineClass offers.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
kind LLMProviderKind | kind is the kind of provider named. | LLMProvider | Enum: [LLMProvider PlatformLLMProvider] Optional: {} |
name string | name is the LLMProvider’s metadata.name, or the platform provider’s name. | MaxLength: 253 MinLength: 1 Required: {} |
LLMProviderSettings
Section titled “LLMProviderSettings”LLMProviderSettings is everything about a model provider except where its keys come from. LLMProvider and the EngineClass’s platform providers share it, so a platform-provided model is described exactly like a tenant’s own. Each field maps onto the same-named field of a Crewlet providers.llm entry.
The cross-field rules over these fields are declared on each type that embeds this one (LLMProviderSpec and PlatformLLMProvider), because controller-gen does not carry a validation declared on an embedded type into the schema of the type that inlines it. The API tests exercise both copies.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
type LLMProviderType | type is which model API the provider speaks. Crewlet’s type. | Enum: [Anthropic OpenAI OpenAICompatible CLIAgent] Required: {} | |
model string | model is the model id requests are sent for, as the provider names it. Crewlet’s model. Crewlet trims it of white space and refuses aprovider with nothing left, as naming no model. | MaxLength: 256 MinLength: 1 Required: {} | |
claudeModel ClaudeModelID | claudeModel names the Claude model whose request shape an Anthropic provider uses when model is a gateway alias Crewlet cannot recognise. Crewlet’s claude_model; type Anthropic only. | Enum: [claude-fable-5-1 claude-mythos-5-1 claude-fable-5 claude-mythos-5 claude-opus-5-5 claude-opus-5 claude-opus-4-8 claude-opus-4-7 claude-sonnet-5-5 claude-sonnet-5 claude-opus-4-6 claude-sonnet-4-6 claude-opus-4-5 claude-sonnet-4-5 claude-haiku-4-5 claude-opus-4-1 claude-opus-4-0 claude-opus-4 claude-sonnet-4-0 claude-sonnet-4 claude-3-7-sonnet] Optional: {} | |
baseURL string | baseURL sends requests to this endpoint instead of the vendor’s own, for a gateway or a proxy. Required for type OpenAICompatible. For type Anthropic it is the gateway’s root, without /v1: Crewlet’s own calls, Claude Code (as ANTHROPIC_BASE_URL) and OpenCode each add the version themselves. A seat’s code work running on the provider hands it to the coding agent in each box. Crewlet’s base_url. | MaxLength: 2048 MinLength: 1 Optional: {} | |
reasoning boolean | reasoning turns on an OpenAI reasoning model’s effort, so that reasoningEffort is sent. Crewlet’s reasoning; type OpenAI only. | Optional: {} | |
reasoningEffort ReasoningEffort | reasoningEffort is how hard the model thinks. For Anthropic it is sent on every call, and unset means High. For OpenAI it is sent only while reasoning is true, so it requires reasoning; an OpenAICompatible provider cannot turn reasoning on and takes no reasoningEffort. Crewlet’s reasoning_effort. | Enum: [Low Medium High XHigh Max] Optional: {} | |
reasoningBudgetTokens integer | reasoningBudgetTokens is the thinking budget of an older, budget-based Claude model. Unset means such a model does not think. Crewlet’s reasoning_budget_tokens; type Anthropic only. | Minimum: 1024 Optional: {} | |
timeoutSeconds integer | timeoutSeconds bounds one HTTP attempt: the whole of a unary call, the longest silence in a streamed one. Unset takes Crewlet’s default of 600. Crewlet’s timeout_seconds. | Minimum: 1 Optional: {} | |
cooldowns LLMCredentialCooldowns | cooldowns is how long a failing key is set aside. Crewlet’scooldowns. | MinProperties: 1 Optional: {} |
LLMProviderSpec
Section titled “LLMProviderSpec”LLMProviderSpec is one model provider of a company. It renders to one entry of Crewlet’s providers.llm, keyed by the LLMProvider’s metadata.name; Seats and the Company’s model order refer to it by that name.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
companyRef CompanyReference | companyRef names the Company this provider belongs to. Immutable. | Required: {} | |
type LLMProviderType | type is which model API the provider speaks. Crewlet’s type. | Enum: [Anthropic OpenAI OpenAICompatible CLIAgent] Required: {} | |
model string | model is the model id requests are sent for, as the provider names it. Crewlet’s model. Crewlet trims it of white space and refuses aprovider with nothing left, as naming no model. | MaxLength: 256 MinLength: 1 Required: {} | |
claudeModel ClaudeModelID | claudeModel names the Claude model whose request shape an Anthropic provider uses when model is a gateway alias Crewlet cannot recognise. Crewlet’s claude_model; type Anthropic only. | Enum: [claude-fable-5-1 claude-mythos-5-1 claude-fable-5 claude-mythos-5 claude-opus-5-5 claude-opus-5 claude-opus-4-8 claude-opus-4-7 claude-sonnet-5-5 claude-sonnet-5 claude-opus-4-6 claude-sonnet-4-6 claude-opus-4-5 claude-sonnet-4-5 claude-haiku-4-5 claude-opus-4-1 claude-opus-4-0 claude-opus-4 claude-sonnet-4-0 claude-sonnet-4 claude-3-7-sonnet] Optional: {} | |
baseURL string | baseURL sends requests to this endpoint instead of the vendor’s own, for a gateway or a proxy. Required for type OpenAICompatible. For type Anthropic it is the gateway’s root, without /v1: Crewlet’s own calls, Claude Code (as ANTHROPIC_BASE_URL) and OpenCode each add the version themselves. A seat’s code work running on the provider hands it to the coding agent in each box. Crewlet’s base_url. | MaxLength: 2048 MinLength: 1 Optional: {} | |
reasoning boolean | reasoning turns on an OpenAI reasoning model’s effort, so that reasoningEffort is sent. Crewlet’s reasoning; type OpenAI only. | Optional: {} | |
reasoningEffort ReasoningEffort | reasoningEffort is how hard the model thinks. For Anthropic it is sent on every call, and unset means High. For OpenAI it is sent only while reasoning is true, so it requires reasoning; an OpenAICompatible provider cannot turn reasoning on and takes no reasoningEffort. Crewlet’s reasoning_effort. | Enum: [Low Medium High XHigh Max] Optional: {} | |
reasoningBudgetTokens integer | reasoningBudgetTokens is the thinking budget of an older, budget-based Claude model. Unset means such a model does not think. Crewlet’s reasoning_budget_tokens; type Anthropic only. | Minimum: 1024 Optional: {} | |
timeoutSeconds integer | timeoutSeconds bounds one HTTP attempt: the whole of a unary call, the longest silence in a streamed one. Unset takes Crewlet’s default of 600. Crewlet’s timeout_seconds. | Minimum: 1 Optional: {} | |
cooldowns LLMCredentialCooldowns | cooldowns is how long a failing key is set aside. Crewlet’scooldowns. | MinProperties: 1 Optional: {} | |
apiKeySecretRefs SecretKeyReference array | apiKeySecretRefs are the provider’s API keys, each a key of a Secret in this namespace. With more than one, Crewlet rotates through them, setting aside a key that hits a rate limit or is refused, in the order listed when several are equally free. Crewlet’s api_keys, acredential position: the values are pushed into the engine’s secret store and the document refers to them by name only. Required for types Anthropic and OpenAI; an OpenAICompatible endpoint that needs no key may omit it. A CLIAgent provider takes exactly one, with cli.auth.mode APIKey, which it gives the CLI. | MaxItems: 16 MinItems: 1 Optional: {} | |
cli CLIAgentSettings | cli is the coding CLI a provider of type CLIAgent drives. Required for, and only for, type CLIAgent. Crewlet’s cli. | Optional: {} |
LLMProviderStatus
Section titled “LLMProviderStatus”LLMProviderStatus is what the operator observed about an LLMProvider.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
conditions Condition array | conditions are Accepted (the Company exists), ResolvedRefs (every Secret key exists), Applied (the provider is in the revision the engine runs) and, on a provider of type CLIAgent in mode Agent, AgentModeRunnable (whether its runs can call a seat’s tools back through the Company’s public address). | MaxItems: 8 Optional: {} | |
observedGeneration integer | observedGeneration is the metadata.generation this status describes. | Minimum: 1 Optional: {} |
LLMProviderType
Section titled “LLMProviderType”Underlying type: string
LLMProviderType is which model API a provider speaks. It maps onto the
type of a Crewlet providers.llm entry: Anthropic is anthropic, OpenAI is
openai, OpenAICompatible is openai-compatible and CLIAgent is
cli-agent.
Validation:
- Enum: [Anthropic OpenAI OpenAICompatible CLIAgent]
Appears in:
| Field | Description |
|---|---|
Anthropic | LLMProviderAnthropic is Anthropic’s Messages API. |
OpenAI | LLMProviderOpenAI is OpenAI’s API. |
OpenAICompatible | LLMProviderOpenAICompatible is any endpoint that speaks the OpenAI wire format: a gateway, an aggregator, a self-hosted inference server. |
CLIAgent | LLMProviderCLIAgent drives a coding CLI (Claude Code, Codex, …) on a subscription login, installed in the engine’s image: see LLMProviderSpec.cli. |
LocalObjectReference
Section titled “LocalObjectReference”LocalObjectReference names another object of the kind the referring field documents, in the referring object’s own namespace.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name is the metadata.name of the referenced object. | MaxLength: 253 MinLength: 1 Required: {} |
MCPCredentialValue
Section titled “MCPCredentialValue”MCPCredentialValue is one value a tool server is started with for a seat: one of its credentials, from a Secret or provisioned by the engine, or a setting that is no credential, written as a literal value. Whether it is an environment variable or a request header depends on the server’s transport, which is why its name follows the grammar of an HTTP header name, of which an environment variable’s name is a subset.
A literal value is for a setting such as a path: slack-mcp-server, for one, keeps the channels its bot can see in a file named after the workspace alone, so each seat names its own (SLACK_MCP_CHANNELS_CACHE), or seats on one engine pod are shown each other’s private channels. Crewlet treats every value of mcp_env as a credential and masks it on every read, and cannot tell a setting from a credential; the name can, so a name that says it holds a credential, as Crewlet reads one (see MCPEnvVar), takes valueFrom.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name is the environment variable’s name (Stdio) or the header’s name (HTTP). | MaxLength: 128 MinLength: 1 Pattern: ^[A-Za-z0-9!#$%&'*+.^_|~-]+$ Required: {} | |
value string | value is a literal value, for a setting that is no credential. It lands in the company document as written, where anyone who can read this object reads it too. An empty string is a valid value, which is why the field is a pointer. | MaxLength: 4096 Optional: {} | |
valueFrom SeatCredentialSource | valueFrom is where a credential comes from: a Secret key, or, for a Seat’s own credentials, the engine (provisioned). For a header the value is the whole header, scheme included (for example “Bearer one for a variable rather than a header. | MinProperties: 1 Optional: {} |
MCPCredentials
Section titled “MCPCredentials”MCPCredentials are the values one tool server is started with for a seat: environment variables for a Stdio server, request headers for an HTTP one. They map onto one server’s entry of Crewlet’s mcp_env, a credential position.
The server is named by a top-level name, as an imagePullSecrets entry names its Secret, rather than by a nested reference, because name is the key of the list that holds these: with a scalar key, server-side apply merges the list entry by entry, so that one field manager (a control plane’s GitHub flow, say) can own the credentials of one server without owning, or overwriting, every other server’s.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name is the metadata.name of the MCPServer, in this namespace, the values are for. | MaxLength: 253 MinLength: 1 Required: {} | |
env MCPCredentialValue array | env are the values. For a Stdio server each is an environment variable of its process; for an HTTP server each is a request header (the name is the header’s name). Names must differ in more than case: HTTP header names are case-insensitive, so Authorization and authorization are one header. | MaxItems: 32 MinItems: 1 Required: {} |
MCPEnvVar
Section titled “MCPEnvVar”MCPEnvVar is one variable of a Stdio tool server’s environment, which every instance of the server starts with: a credential, read from a Secret, or a setting that is no credential, written as a literal value, such as the address of the service the server reaches or a switch that turns one of its tools on.
Crewlet treats a server’s whole environment as credentials, masking every value on every read, so it cannot tell the two apart; a name can. A name says it holds a credential when one of its parts, cut at every character that is not a letter or a digit and read without case, is KEY, KEYS, APIKEY, ACCESSKEY, SECRETKEY, TOKEN, SECRET, PASSWORD, PASSWD, CREDENTIAL, CREDENTIALS, AUTH, OAUTH or PAT, which is how Crewlet itself reads a credential’s name (cliprofile.IsCredentialName), or when it is one of the HTTP headers that carry one, Authorization, Proxy-Authorization and Cookie; such a name takes valueFrom, never a literal. So GITLAB_TOKEN, TAVILY_API_KEY and X-Api-Key come from Secrets, and JIRA_URL or SLACK_MCP_ADD_MESSAGE_TOOL may be written out. The rule keeps a credential from being typed where a setting goes; a credential under a name that says nothing (a URL with a password in it, say) is still yours to keep in a Secret.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name is the variable’s name. | MaxLength: 128 MinLength: 1 Pattern: ^[A-Za-z_][A-Za-z0-9_]*$ Required: {} | |
value string | value is a literal value, for a setting that is no credential. It lands in the company document as written, where anyone who can read this object reads it too. An empty string is a valid value, which is why the field is a pointer. | MaxLength: 4096 Optional: {} | |
valueFrom SecretValueSource | valueFrom reads a credential from a Secret key. | Optional: {} |
MCPHeader
Section titled “MCPHeader”MCPHeader is one header of every request to an HTTP tool server, which every instance of the server sends: a credential, read from a Secret, such as the Authorization header, or a setting that is no credential, written as a literal value, by the rule MCPEnvVar states.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name is the header’s name. | MaxLength: 128 MinLength: 1 Pattern: ^[A-Za-z0-9!#$%&'*+.^_|~-]+$ Required: {} | |
value string | value is a literal value, for a setting that is no credential. It lands in the company document as written, where anyone who can read this object reads it too. An empty string is a valid value, which is why the field is a pointer. | MaxLength: 4096 Optional: {} | |
valueFrom SecretValueSource | valueFrom reads a credential from a Secret key, which holds the whole header value, scheme included (for example “Bearer | Optional: {} |
MCPServer
Section titled “MCPServer”MCPServer is a Model Context Protocol tool server a company’s agents call.
The name crewlet is reserved: the engine gives a seat’s own tool bridge that name inside a coding agent’s sandbox.
| Field | Description | Default | Validation |
|---|---|---|---|
apiVersion string | crewlet.ai/v1alpha1 | ||
kind string | MCPServer | ||
metadata ObjectMeta | Refer to Kubernetes API documentation for fields of metadata. | Optional: {} | |
spec MCPServerSpec | spec is the server’s desired state. | Required: {} | |
status MCPServerStatus | status is the server’s observed state. | MinProperties: 1 Optional: {} |
MCPServerSpec
Section titled “MCPServerSpec”MCPServerSpec is one tool server a company’s agents call. It renders to one entry of Crewlet’s mcp_servers, named by the MCPServer’s metadata.name; Seats and Units give it per-seat values by that name.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
companyRef CompanyReference | companyRef names the Company this server belongs to. Immutable. | Required: {} | |
transport MCPTransport | transport is how the engine reaches the server. Crewlet’s transport. | Stdio | Enum: [Stdio HTTP] Optional: {} |
shared boolean | shared launches one instance whose tools every agent calls. false makes the server a template instead: every agent seat that names it in spec.mcp, its own or its unit’s, gets an instance of its own, which is how each agent acts as itself on the server. An entry of settings alone starts one too, with none of the seat’s credentials. Crewlet’s shared. | true | Optional: {} |
command string | command is the executable a Stdio server is launched with, as a process of the engine’s container, by the engine’s user. It must be installed in the engine image, and Crewlet’s image ships no Python or Node.js runtime (docs/guides/tool-servers.md). Crewlet’s command, which itpasses on as written: it resolves no ${NAME} in it. | MaxLength: 1024 MinLength: 1 Optional: {} | |
args string array | args are the executable’s arguments. Crewlet’s args, which it passeson as written: it resolves no ${NAME} in them. | MaxItems: 64 items:MaxLength: 4096 Optional: {} | |
env MCPEnvVar array | env is the environment of a Stdio server’s process, shared by every instance; per-seat values belong in a Seat’s or a Unit’s spec.mcp, which win over these. It is laid over the part of the engine’s own environment Crewlet hands a tool server: PATH, the locale, the TLS and proxy variables and the engine user’s HOME, among a few others (docs/guides/tool-servers.md). Nothing else of the engine’s environment reaches the server: a variable the engine image sets with ENV, or the class or the Company sets on the pod, reaches it only when it is one of those, so every other variable the server reads is given here. Crewlet’s env, a credential position. | MaxItems: 32 Optional: {} | |
url string | url is the endpoint of an HTTP server. Crewlet’s url. | MaxLength: 2048 MinLength: 1 Optional: {} | |
headers MCPHeader array | headers are sent with every request to an HTTP server, shared by every instance; per-seat values belong in a Seat’s or a Unit’s spec.mcp. Header names are case-insensitive, so names must differ in more than case. Crewlet’s headers, a credential position. | MaxItems: 32 Optional: {} | |
optionalKeys string array | optionalKeys names the keys whose value may go missing: variables of env (Stdio) or headers (HTTP), and the values every Seat and Unit gives the server in spec.mcp, which land in the same environment or the same headers. Crewlet starts a server only once every value it is started with has one, so a value read from a Secret that does not exist, holds no such key or holds an empty value keeps the server from starting. Under a key listed here, such a value is left out instead, whole: the server starts without the variable, or its requests go without the header, as Kubernetes starts a container without an optional secretKeyRef. A missing Secret or key under one is then no failure of the references of the object that gives the value, and holds nothing back. Under the Enforce policy the operator also takes the value it pushed for it out of the engine’s secret store, and has the engine read the store again whether or not the document can be applied, so the server is not started again with a deleted Secret’s value, but by a revision the engine runs that reads the key as required (one from before the key was listed) or whose reading the operator does not know (another document somebody else activated), which keeps the value until the next document runs, and that one is activated once with it and at once again without it; a Secret key that is also read where it is required holds the document while it is missing, and keeps the value it had in a revision the engine runs that requires it too until the document applies. A Seat’s or a Unit’s value for a key replaces the server’s whole, so one that goes missing leaves the key out rather than handing the server’s own value back; and a provisioned value an Integration mints for a seat is waited for whatever this says. Every entry must name a key at least one value read from a Secret, or provisioned, is written under, here or in a Seat’s or a Unit’s spec.mcp for this server: one under which every value is a literal, which is never missing, or no value at all, leaves nothing out and holds the document (ResolvedRefs=False with OptionalKeyUnused), as Crewlet refuses it. A Stdio server’s keys are compared as written, an HTTP server’s without case, as headers are. Crewlet’s optional_keys. | MaxItems: 32 items:MaxLength: 128 items:MinLength: 1 items:Pattern: ^[A-Za-z0-9!#$%&'*+.^_|~-]+$ Optional: {} | |
toolPrefix string | toolPrefix is put in front of the server’s tool names, to keep them apart from another server’s. Crewlet’s tool_prefix. | MaxLength: 32 MinLength: 1 Pattern: ^[A-Za-z][A-Za-z0-9_-]*$ Optional: {} | |
toolAnnotations MCPToolAnnotations array | toolAnnotations correct the hints individual tools advertise. Crewlet’s tool_annotations. | MaxItems: 128 Optional: {} | |
startupTimeoutSeconds integer | startupTimeoutSeconds bounds starting the server and the handshake, and separately its first tool listing, so a start can take up to twice it before Crewlet gives the server up. Unset takes Crewlet’s default of 120. Crewlet’s startup_timeout_seconds. | Minimum: 1 Optional: {} | |
requestTimeoutSeconds integer | requestTimeoutSeconds bounds one tool call. Unset takes Crewlet’s default of 300. Crewlet’s request_timeout_seconds. | Minimum: 1 Optional: {} |
MCPServerStatus
Section titled “MCPServerStatus”MCPServerStatus is what the operator observed about an MCPServer.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
conditions Condition array | conditions are Accepted (the Company exists), ResolvedRefs (every Secret key exists) and Applied (the server is in the revision the engine runs). | MaxItems: 8 Optional: {} | |
observedGeneration integer | observedGeneration is the metadata.generation this status describes. | Minimum: 1 Optional: {} |
MCPToolAnnotations
Section titled “MCPToolAnnotations”MCPToolAnnotations corrects the behavioural hints one tool advertises. The engine decides from them what a tool may be used for, such as whether a delegated worker may call it. Each field maps onto Crewlet’s tool_annotations entry; unset keeps what the server says.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
tool string | tool is the tool’s name as the server publishes it, without any prefix. | MaxLength: 128 MinLength: 1 Required: {} | |
readOnly boolean | readOnly marks a tool that changes nothing. Crewlet’s read_only. | Optional: {} | |
destructive boolean | destructive marks a tool whose effect cannot be undone. Crewlet’sdestructive. | Optional: {} | |
idempotent boolean | idempotent marks a tool that can be repeated safely. Crewlet’sidempotent. | Optional: {} | |
openWorld boolean | openWorld marks a tool that reaches outside the company. Crewlet’sopen_world. | Optional: {} |
MCPTransport
Section titled “MCPTransport”Underlying type: string
MCPTransport is how the engine reaches a tool server. It maps onto
Crewlet’s mcp_servers[].transport (Stdio is stdio, HTTP is http).
Validation:
- Enum: [Stdio HTTP]
Appears in:
| Field | Description |
|---|---|
Stdio | MCPTransportStdio launches the server as a process next to the engine and speaks to it over its standard input and output. The command must exist in the engine image. |
HTTP | MCPTransportHTTP connects to a remote server over Streamable HTTP. |
ManagedKind
Section titled “ManagedKind”Underlying type: string
ManagedKind is the kind of object a seat manages.
Validation:
- Enum: [Seat Unit]
Appears in:
| Field | Description |
|---|---|
Seat | ManagedKindSeat is a single Seat. |
Unit | ManagedKindUnit is every seat of a Unit and of the units below it. |
ManagedReference
Section titled “ManagedReference”ManagedReference names a Seat or a Unit, in the referring Seat’s namespace, that a seat manages.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
kind ManagedKind | kind is the kind of object named. | Seat | Enum: [Seat Unit] Optional: {} |
name string | name is the object’s metadata.name. | MaxLength: 253 MinLength: 1 Required: {} |
ManagementPolicy
Section titled “ManagementPolicy”Underlying type: string
ManagementPolicy says who owns a company’s live document.
Validation:
- Enum: [Enforce Observe Seed]
Appears in:
| Field | Description |
|---|---|
Enforce | ManagementPolicyEnforce makes the operator the document’s only writer. The engine refuses every other credential a change to the document (403 config_managed), the published access token and a person signed in at its dashboard included, and its dashboard shows the document read-only; a revision made some other way all the same (the engine’s own writes, or one made before the data pod restarted onto the policy) is reported and overwritten. |
Observe | ManagementPolicyObserve renders and compares, and never writes; a difference is reported only. The engine’s own users may change the document. |
Seed | ManagementPolicySeed writes the document once, into an engine that has none, and then leaves it to the engine and its dashboard, whose users may change it. Changes to the Company’s children are ignored afterwards and say so in their status. |
MattermostEngineProvisioning
Section titled “MattermostEngineProvisioning”MattermostEngineProvisioning is how the engine provisions the seats’ Mattermost bots under provisioning Engine. It maps onto Crewlet’s integrations.mattermost.provisioning: for each agent seat whose spec.integrations.mattermost.botToken is provisioned, the engine creates a bot, adds it to the team and the channels, and mints its token into that value.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
adminTokenSecretRef SecretKeyReference | adminTokenSecretRef is the Secret key holding a system administrator’s personal access token, which creates and disables the bots. Crewlet’s admin_token, a credential position. | Required: {} | |
usernamePrefix string | usernamePrefix is put before each seat’s handle to form its bot’s username, for a server shared with people. Crewlet’s username_prefix. | MaxLength: 32 MinLength: 1 Pattern: ^[a-z0-9._-]+$ Optional: {} | |
channels string array | channels are channels, by name (the URL slug), every bot joins: a bot hears only the channels it is in. Crewlet’s channels. | MaxItems: 64 items:MaxLength: 64 items:MinLength: 1 items:Pattern: ^[a-z0-9][a-z0-9_-]*$ Optional: {} | |
displayNameSuffix string | displayNameSuffix is put after each bot’s display name, such as ” (AI)”, to tell agents from people at a glance. Crewlet’s display_name_suffix. | MaxLength: 64 MinLength: 1 Optional: {} |
MattermostIntegration
Section titled “MattermostIntegration”MattermostIntegration turns Mattermost on for a company. It maps onto Crewlet’s integrations.mattermost. Mattermost delivers no webhook the engine can use: the engine holds a websocket per seat’s bot instead, so the integration needs no public address. Each seat’s bot is in its Seat’s spec.integrations.mattermost.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
url string | url is the address the engine reaches the server at, such as https://chat.example.com: each seat’s websocket, the REST calls and the bots’ provisioning go to it. It need not be the server’s Site URL, which people browse and from which Mattermost builds its links; the engine builds none from url. Any route to the server serves, such as its in-cluster Service: the engine’s websockets carry no Origin header, so Mattermost’s origin check, which holds a browser to the Site URL, never applies to them. The server has to answer its API at url without a redirect, which neither the engine nor the seats’ Mattermost tool server, given the same address as its MATTERMOST_URL, follows: on the scheme that address is served on, and at the Site URL’s path, outside which Mattermost redirects every request. Crewlet’s url. | MaxLength: 2048 MinLength: 1 Required: {} | |
team string | team is the team, by name (the URL slug), the bots belong to. Crewlet’s team. | MaxLength: 64 MinLength: 1 Pattern: ^[a-z0-9][a-z0-9_-]*$ Required: {} | |
typingStatus WorkingStatus | typingStatus is when a seat shows that it is typing. Unset takes Crewlet’s default, Always; each indicator costs a request every few seconds while the seat works. Crewlet’s typing_status. | Enum: [Always Addressed] Optional: {} | |
engineProvisioning MattermostEngineProvisioning | engineProvisioning is how the engine creates the seats’ bots. Required with provisioning Engine, and not allowed with External. | Optional: {} |
MattermostSeatIntegration
Section titled “MattermostSeatIntegration”MattermostSeatIntegration is a seat’s own Mattermost bot. It maps onto Crewlet’s role integrations.mattermost and needs the company’s Mattermost Integration. One credential covers everything the bot does: the websocket the engine listens on, its REST calls, and the Mattermost tool server, whose credentials (in spec.mcp) name the same token.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
botToken SeatCredentialSource | botToken is the bot account’s personal access token: from a Secret, or provisioned by the engine under a Mattermost Integration with provisioning Engine, which creates the bot and mints the token. Crewlet’s bot_token, a credential position. | MinProperties: 1 Required: {} | |
username string | username is the bot’s username, for a bot that exists under a name other than the seat’s handle (with the Integration’s engineProvisioning.usernamePrefix before it). Crewlet’s username. | MaxLength: 64 MinLength: 1 Pattern: ^[a-z0-9][a-z0-9._-]*$ Optional: {} | |
channel string | channel is a channel, by its name (the URL slug), the engine adds the bot to when it provisions it, on top of the Integration’s engineProvisioning.channels. Crewlet’s channel. | MaxLength: 64 MinLength: 1 Pattern: ^[a-z0-9][a-z0-9_-]*$ Optional: {} |
NamespacedSecretKeyReference
Section titled “NamespacedSecretKeyReference”NamespacedSecretKeyReference selects one key of a Secret in a named namespace. Only the cluster-scoped EngineClass uses it: a platform-owned value (a managed LLM key, telemetry headers) lives in a namespace the platform controls rather than in each tenant’s. The value itself still reaches every tenant that runs with it (see the field that references it); the namespace keeps tenants from the platform’s Secret, not from the value.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
namespace string | namespace is the namespace the Secret is in. | MaxLength: 63 MinLength: 1 Required: {} | |
name string | name is the metadata.name of the Secret. | MaxLength: 253 MinLength: 1 Required: {} | |
key string | key is the key within the Secret’s data. | MaxLength: 253 MinLength: 1 Pattern: ^[-._a-zA-Z0-9]+$ Required: {} |
NamespacedSecretValueSource
Section titled “NamespacedSecretValueSource”NamespacedSecretValueSource says where a value set by the cluster-scoped EngineClass comes from: a Secret in a namespace the platform controls.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
secretKeyRef NamespacedSecretKeyReference | secretKeyRef selects the Secret key that holds the value. | Required: {} |
NativeTrackerSettings
Section titled “NativeTrackerSettings”NativeTrackerSettings is the policy of the engine’s own tracker. It maps onto Crewlet’s tracker.native.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
inboxRetentionDays integer | inboxRetentionDays is how long a person’s inbox keeps a row; the history the row points at is kept regardless. Unset takes Crewlet’s default of 365. Crewlet’s inbox_retention_days. | Maximum: 3650 Minimum: 30 Optional: {} |
NetworkPolicyEgress
Section titled “NetworkPolicyEgress”NetworkPolicyEgress is where the engine may connect to, beyond DNS and its own namespace.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
exceptCIDRs string array | exceptCIDRs are address blocks the engine may not reach, besides the cloud metadata endpoints. List the cluster’s pod, Service and node networks here: a NetworkPolicy has no other way to tell an address in the cluster from one outside it, and without them an engine reaches other tenants’ pods, the Kubernetes API server and the nodes. Each is a canonical IPv4 or IPv6 CIDR, narrower than the whole address space. | MaxItems: 32 MinItems: 1 items:MaxLength: 43 Optional: {} | |
to NetworkPolicyPeer array | to are pods in the cluster the engine may reach although exceptCIDRs covers them: an in-cluster model gateway, the telemetry collector, an object store. | MaxItems: 16 MinItems: 1 Optional: {} |
NetworkPolicyMode
Section titled “NetworkPolicyMode”Underlying type: string
NetworkPolicyMode is whether the operator restricts traffic to the engine.
Validation:
- Enum: [Isolated None]
Appears in:
| Field | Description |
|---|---|
Isolated | NetworkPolicyIsolated admits traffic to the engine’s API port only from the operator’s pods, from the namespaces the Gateway proxies or Ingress controller of the class’s API route run in (gateway.proxyNamespaces, ingress.controllerNamespaces), and from the class’s apiConsumers; to its public port only from where the webhooks’ route arrives from (the same fields of exposure.webhooks, or webhooks.external.forwarders); and lets the engine connect only as networkPolicy.egress says. It needs a CNI that enforces NetworkPolicy, egress included. |
None | NetworkPolicyNone creates no NetworkPolicy. |
NetworkPolicyPeer
Section titled “NetworkPolicyPeer”NetworkPolicyPeer is the pods its podSelector selects in the namespaces its namespaceSelector selects, as a NetworkPolicy peer that sets both.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
namespaceSelector LabelSelector | namespaceSelector selects namespaces by their labels; an empty one selects every namespace. Select a namespace by name with the label kubernetes.io/metadata.name, which the API server sets on every namespace. | Required: {} | |
podSelector LabelSelector | podSelector selects pods in those namespaces by their labels. Unset selects every pod in them. | Optional: {} |
NetworkPolicySettings
Section titled “NetworkPolicySettings”NetworkPolicySettings is the NetworkPolicy the operator puts around each company’s engine pods.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
mode NetworkPolicyMode | mode is whether the operator restricts the engine’s traffic. | Isolated | Enum: [Isolated None] Optional: {} |
apiConsumers NetworkPolicyPeer array | apiConsumers are the pods admitted to the engine’s API port besides the operator and the Gateway proxies or Ingress controller of the class’s API route, and to nothing else of the engine (the public port, which the webhooks reach, admits only where they arrive from): the platform’s own components (a control plane, a dashboard) that call the engines of this class’s companies. Each holds an access token, which the engine still requires. | MaxItems: 16 MinItems: 1 Optional: {} | |
egress NetworkPolicyEgress | egress narrows where the engine may connect to. The engine runs code the tenant supplies in its pod (stdio MCP servers, coding CLIs, and what its agents have them do), so under Isolated its pods may reach DNS, the pods of their own namespace, and every address outside the cluster except the cloud metadata endpoints (169.254.169.254, fd00:ec2::254), which hand out the node’s credentials. What else is in the cluster is unreachable only if listed in exceptCIDRs. A seat’s code work and an agent-mode executor’s run, the sandbox’s setup commands included, run in the Company’s E2B sandbox, which this policy does not reach. | MinProperties: 1 Optional: {} |
ObjectBackend
Section titled “ObjectBackend”Underlying type: string
ObjectBackend is where a company’s files are kept. It maps onto Crewlet’s
store.objects.backend (NATS is nats, S3 is s3).
Validation:
- Enum: [NATS S3]
Appears in:
| Field | Description |
|---|---|
NATS | ObjectBackendNATS keeps files in a bucket on the company’s own event stream, on the data volume. |
S3 | ObjectBackendS3 keeps files in an S3-compatible bucket. |
ObjectSettings
Section titled “ObjectSettings”ObjectSettings is where a class’s companies keep their files.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
backend ObjectBackend | backend is where files are kept. Changing it does not move existing files. | NATS | Enum: [NATS S3] Optional: {} |
s3 S3ObjectSettings | s3 is the bucket, for backend S3. | Optional: {} |
PlatformLLMProvider
Section titled “PlatformLLMProvider”PlatformLLMProvider is a model provider the platform offers to every Company of a class that sets spec.llm.usePlatformProviders. Its keys live in a namespace the platform controls and are pushed into the secret store of each opted-in company’s engine.
That store is the tenant’s to read: the engine’s API reveals any value in it to whoever holds the company’s access token (status.apiAccessSecretRef of the Company), and code the tenant runs in the engine’s pod can open it with the keyring the pod holds. So every opted-in tenant can read these keys. Offer keys you would give each of them: one per tenant, or the per-tenant virtual keys of an LLM gateway, never the platform’s own.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name is the provider’s name. Seats and the Company’s model order refer to it with kind PlatformLLMProvider. It may not be default, which Crewlet would run every chainless seat of every opted-in company on, whatever the company’s own order says. | MaxLength: 63 MinLength: 1 Pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ Required: {} | |
type LLMProviderType | type is which model API the provider speaks. Crewlet’s type. | Enum: [Anthropic OpenAI OpenAICompatible CLIAgent] Required: {} | |
model string | model is the model id requests are sent for, as the provider names it. Crewlet’s model. Crewlet trims it of white space and refuses aprovider with nothing left, as naming no model. | MaxLength: 256 MinLength: 1 Required: {} | |
claudeModel ClaudeModelID | claudeModel names the Claude model whose request shape an Anthropic provider uses when model is a gateway alias Crewlet cannot recognise. Crewlet’s claude_model; type Anthropic only. | Enum: [claude-fable-5-1 claude-mythos-5-1 claude-fable-5 claude-mythos-5 claude-opus-5-5 claude-opus-5 claude-opus-4-8 claude-opus-4-7 claude-sonnet-5-5 claude-sonnet-5 claude-opus-4-6 claude-sonnet-4-6 claude-opus-4-5 claude-sonnet-4-5 claude-haiku-4-5 claude-opus-4-1 claude-opus-4-0 claude-opus-4 claude-sonnet-4-0 claude-sonnet-4 claude-3-7-sonnet] Optional: {} | |
baseURL string | baseURL sends requests to this endpoint instead of the vendor’s own, for a gateway or a proxy. Required for type OpenAICompatible. For type Anthropic it is the gateway’s root, without /v1: Crewlet’s own calls, Claude Code (as ANTHROPIC_BASE_URL) and OpenCode each add the version themselves. A seat’s code work running on the provider hands it to the coding agent in each box. Crewlet’s base_url. | MaxLength: 2048 MinLength: 1 Optional: {} | |
reasoning boolean | reasoning turns on an OpenAI reasoning model’s effort, so that reasoningEffort is sent. Crewlet’s reasoning; type OpenAI only. | Optional: {} | |
reasoningEffort ReasoningEffort | reasoningEffort is how hard the model thinks. For Anthropic it is sent on every call, and unset means High. For OpenAI it is sent only while reasoning is true, so it requires reasoning; an OpenAICompatible provider cannot turn reasoning on and takes no reasoningEffort. Crewlet’s reasoning_effort. | Enum: [Low Medium High XHigh Max] Optional: {} | |
reasoningBudgetTokens integer | reasoningBudgetTokens is the thinking budget of an older, budget-based Claude model. Unset means such a model does not think. Crewlet’s reasoning_budget_tokens; type Anthropic only. | Minimum: 1024 Optional: {} | |
timeoutSeconds integer | timeoutSeconds bounds one HTTP attempt: the whole of a unary call, the longest silence in a streamed one. Unset takes Crewlet’s default of 600. Crewlet’s timeout_seconds. | Minimum: 1 Optional: {} | |
cooldowns LLMCredentialCooldowns | cooldowns is how long a failing key is set aside. Crewlet’scooldowns. | MinProperties: 1 Optional: {} | |
apiKeySecretRefs NamespacedSecretKeyReference array | apiKeySecretRefs are the provider’s API keys, rotated as an LLMProvider’s are. | MaxItems: 16 MinItems: 1 Optional: {} |
ProvisionedCredential
Section titled “ProvisionedCredential”ProvisionedCredential is a seat’s credential the engine creates: an Integration with provisioning Engine (GitLab, Mattermost, Datadog, Atlassian) makes the seat’s account at the vendor, mints the account’s credential, and seals it in the engine’s own secret store. The company document refers to it by a name the operator derives from the seat’s handle and this name, and nothing else ever writes that store entry: the operator pushes no value into it and deletes none it finds there.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name names the value among the seat’s provisioned credentials. Every place a seat names the same provisioned name refers to one value, so a token given to a tool server’s environment and to the seat’s sandbox is one token; different names are different values, such as an account’s token and its email address. | MaxLength: 32 MinLength: 1 Pattern: ^[a-z0-9][a-z0-9-]*$ Required: {} |
ReasoningEffort
Section titled “ReasoningEffort”Underlying type: string
ReasoningEffort is how hard a model thinks. It maps onto Crewlet’s
reasoning_effort (Low is low, XHigh is xhigh, and so on).
Validation:
- Enum: [Low Medium High XHigh Max]
Appears in:
| Field | Description |
|---|---|
Low | |
Medium | |
High | |
XHigh | |
Max |
RetentionSettings
Section titled “RetentionSettings”RetentionSettings is who answers for a class’s companies’ backups.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
backupOwner string | backupOwner names whoever is responsible for backing up the companies’ data volumes; the engine warns while none is named. Crewlet’s retention.backup_owner. | MaxLength: 256 MinLength: 1 Required: {} |
RevisionPlacement
Section titled “RevisionPlacement”RevisionPlacement is where a revision of the company document pins its agent seats: the values of the two placement labels its roles name. Only values that can name one of the company’s pods are recorded: a pool name and a seat handle.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
pools string array | pools are the values of the crewlet.ai/pool placement label: data, and each Shared pool a seat is pinned to. | MaxItems: 64 items:MaxLength: 20 items:MinLength: 1 items:Pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ Optional: {} | |
seats string array | seats are the values of the crewlet.ai/seat placement label: the handle of each seat pinned to its own pods in a PerSeat pool. A revision that pins more seats than the list holds records the first in handle order; the pods of the others are kept only while their seats stay in a PerSeat pool. | MaxItems: 1024 items:MaxLength: 63 items:MinLength: 1 items:Pattern: ^[a-z0-9][a-z0-9-]*$ Optional: {} |
S3ObjectSettings
Section titled “S3ObjectSettings”S3ObjectSettings is the S3-compatible bucket a class’s companies keep their files in. Each field maps onto the same-named field of Crewlet’s store.objects.s3.
The bucket’s credentials are each Company’s own (its spec.objects.credentialsSecretRef), not the class’s: whatever reaches a company’s engine pod is readable by code the tenant runs there (a stdio MCP server, a coding CLI), so a key the class shared would let every tenant read and write every other tenant’s files.
Crewlet reaches the bucket when it starts (a HeadBucket request, on the data pods and the seat pods alike), and refuses to start when it cannot. Some settings fail that request before it is sent, through the S3 client Crewlet is built with (the AWS SDK for Go), however the bucket is set up, so the API refuses them where they are written rather than every pod crash-looping on them: each rule below names one.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
endpoint string | endpoint is the S3 API’s base URL. Unset is Amazon S3’s own endpoint for the region. Crewlet’s S3 client refuses at start an endpoint with a query, one whose host is not a name, an IPv4 address or an IPv6 address in brackets (with no percent-encoding in its zone) followed by at most one port, and no connection is made on a port outside 1 to 65535, so the API refuses each. | MaxLength: 2048 MinLength: 1 Optional: {} | |
region string | region is the bucket’s region. Every request is signed for one, even where the provider ignores it (Cloudflare R2: auto, MinIO: us-east-1). Crewlet’s S3 client puts it into a host name, and refuses at start a region that is not one: letters, digits and ’-’ in labels of at most 63 joined by ’.’, none starting or ending with ’-’. Crewlet trims the white space around it first, and refuses one of white space alone. | MaxLength: 64 MinLength: 1 Required: {} | |
bucket string | bucket is the bucket’s name: a general purpose bucket’s. Crewlet’s S3 client reads a name that begins with arn: as an access point’s ARN, and one that ends with —x-s3, —xa-s3 or —op-s3 as an S3 Express One Zone directory bucket or an Outposts access point alias, each of which it addresses in a way of its own and refuses at start where it cannot, so the API refuses those names. Crewlet trims the white space around it, and refuses one of white space alone. | MaxLength: 63 MinLength: 3 Required: {} | |
prefix string | prefix is Crewlet’s store.objects.s3.prefix, prepended to every key as it is, so that one bucket holds many companies. It is a template: {{namespace}}, {{name}} and {{uid}} are replaced by the Company’s namespace, name and UID, and the result must differ between companies, so it must contain {{uid}}, or {{namespace}} and {{name}} joined by a ’/’ or ’.’, which neither can hold (with a ’-’ between them, team-a/b-web and team-a-b/web would share keys); and it ends with ’/’, so that no company’s prefix starts another’s. The default keys files by namespace and name, which is also what the data volumes are named by: a Company re-created under its old name after a Retain deletion finds both its estate and its files again. | {{namespace}}/{{name}}/ | MaxLength: 256 MinLength: 1 Optional: {} |
pathStyle boolean | pathStyle addresses the bucket in the URL path rather than in the host name; MinIO and most self-hosted gateways need it. | Optional: {} |
SandboxFile
Section titled “SandboxFile”SandboxFile is a file written into a sandbox before its commands run. Its content is a credential position in Crewlet (it typically holds a git or registry login), so it always comes from a Secret.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
path string | path is where the file is written in the seat’s E2B box. The box’s own agent writes it as the account every template runs as, and creates any directory it needs. A relative path, such as .npmrc, and one starting ~/ are joined onto that account’s home, /home/user, and cleaned, so one that climbs with .. (../x) lands outside the home. An absolute path is written where it names, which works only where that account may write (not under /root, for one). Crewlet’s files key.The box refuses a path that names a directory rather than a file, and a path starting ~ and a name, such as ~root/.npmrc, since it does not expand another account’s home. A path naming a directory only the template made, such as /tmp, fails every box at setup: nothing can tell beforehand. Crewlet refuses a company document that gives a seat’s box one of the shapes it can judge without the template: another account’s home, and the home or a directory above it (such as ~, . or /home), which every template has. It also refuses a path of white space alone on every step. The API refuses white space alone and another account’s home itself. Whether a path names the home depends on how .. and repeated separators resolve, so that is left to Crewlet, whose refusal is reported on the Company as ConfigApplied=False Invalid for a step of the Company’s own, and on the Seat as Applied=False Invalid for a step of a Seat’s. Either way the document is held and the running revision stays. | MaxLength: 1024 MinLength: 1 Required: {} | |
valueFrom SecretValueSource | valueFrom is the Secret key holding the file’s content. | Required: {} |
SandboxSettings
Section titled “SandboxSettings”SandboxSettings is where a company’s seats run code. It maps onto Crewlet’s providers.sandbox.
v1alpha1 offers Crewlet’s remote sandbox (E2B) only. Crewlet’s local
placements are not offered: direct would run every seat’s code inside the
engine pod with the engine’s own credentials, and container needs a
container runtime a pod does not have.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
e2b E2BSandbox | e2b is the remote sandbox service. | Required: {} | |
defaultCodingAgent CodingAgent | defaultCodingAgent is the coding agent of seats that name none. Crewlet’s default_coding_agent. | Enum: [ClaudeCode OpenCode] Optional: {} | |
defaultTimeoutSeconds integer | defaultTimeoutSeconds is how long a sandbox outlives an engine that stopped renewing it. It never stops a running job. Crewlet’s default_timeout_seconds. | Minimum: 1 Optional: {} | |
defaultPauseTTLSeconds integer | defaultPauseTTLSeconds is how long a sandbox waiting on a person’s answer stays paused before it is reclaimed. Unset takes Crewlet’s default of 1800; 0 never pauses. Crewlet’s default_pause_ttl_seconds. | Minimum: 0 Optional: {} | |
defaultMaxTurns integer | defaultMaxTurns caps the agentic rounds of a coding run on seats that name none. Unset or 0 is uncapped. Crewlet’s default_max_turns. | Minimum: 0 Optional: {} | |
setup SandboxSetupStep array | setup is applied to every sandbox before each seat’s own steps. Crewlet’s setup. | MaxItems: 16 Optional: {} |
SandboxSetupStep
Section titled “SandboxSetupStep”SandboxSetupStep is one provisioning step applied to a sandbox before the coding agent starts. It maps onto a Crewlet sandbox setup step, which Crewlet refuses when it does nothing (no files, commands, env or brief): that is almost always an unfinished edit, which would otherwise apply cleanly for ever and look like it was working.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name identifies the step in logs and failure messages, so Crewlet refuses one of white space alone, and so does the API. | MaxLength: 63 MinLength: 1 Required: {} | |
files SandboxFile array | files are written into the sandbox before the commands run. Crewlet’sfiles, a credential position. | MaxItems: 16 Optional: {} | |
commands string array | commands are shell commands run in order; one that exits non-zero fails the sandbox. Crewlet’s commands. Crewlet resolves nothing in acommand: the sandbox’s login shell expands $NAME and ${NAME} from the box’s own environment (its HOME and PATH among it) and the run’s, never from the engine’s. The run’s is the steps’ env, the Seat’s sandbox env, and what Crewlet adds: the agent’s handle and, when it has one, its email, and the variables that sign the coding agent in to the provider its code work runs on, or, in an agent-mode executor’s run, those of the executor’s own provider (docs/guides/credentials.md says which, and when the seat’s own env leaves them out). The API refuses ${NAME} (NAME an identifier) all the same, as the operator refuses every ${NAME} it did not write in a string it renders: write a sandbox variable as $NAME. Parameter expansions such as ${1:-x} are allowed. | MaxItems: 32 items:MaxLength: 4096 items:MinLength: 1 Optional: {} | |
env SecretEnvVar array | env is merged into the environment of the commands and of the run. Crewlet’s env, a credential position. | MaxItems: 32 Optional: {} | |
optionalKeys string array | optionalKeys names variables of env, and paths of files, whose value may go missing. Crewlet refuses to start a run_sandbox coding run whose environment or files hold a value that does not resolve: a Secret that does not exist, holds no such key or holds an empty value. Under an entry listed here, such a variable is left out of the run and such a file is not written, and the run starts without it. A missing Secret or key under one is then no failure of the object’s references and holds nothing back. Under the Enforce policy the operator also takes the value it pushed for it out of the engine’s secret store, and has the engine read the store again whether or not the document can be applied, so no run starts with a deleted Secret’s value, but in a revision the engine runs that reads the key as required (one from before the key was listed) or whose reading the operator does not know (another document somebody else activated), which keeps the value until the next document runs, and that one is activated once with it and at once again without it; a Secret key that is also read where it is required holds the document while it is missing, and keeps the value it had in a revision the engine runs that requires it too until the document applies. A later step’s variable of the same name wins over this one’s, and the Seat’s spec.sandbox.env over every step’s, and the list beside the value that wins is the one that counts for it; a file is the step’s own. Crewlet’s optional_keys. | MaxItems: 48 items:MaxLength: 1024 items:MinLength: 1 Optional: {} | |
brief string | brief tells the coding agent what this step made true about the sandbox. | MaxLength: 2048 MinLength: 1 Optional: {} | |
timeoutSeconds integer | timeoutSeconds caps each command of the step. | Minimum: 1 Optional: {} |
Schedule
Section titled “Schedule”Schedule is recurring work a seat or a unit owns, fired on a cron schedule: the CronJob of a company.
The Schedule’s metadata.name is the schedule’s name in the engine, which is half of the identity the engine claims each fire under, so that a fire runs once however often the engine evaluates its minute. Two Schedules of one seat or unit therefore never share a name, and a fire is never run twice.
A fire that comes due while its seat is paused is skipped, not queued.
| Field | Description | Default | Validation |
|---|---|---|---|
apiVersion string | crewlet.ai/v1alpha1 | ||
kind string | Schedule | ||
metadata ObjectMeta | Refer to Kubernetes API documentation for fields of metadata. | Optional: {} | |
spec ScheduleSpec | spec is the schedule’s desired state. | Required: {} | |
status ScheduleStatus | status is the schedule’s observed state. | MinProperties: 1 Optional: {} |
ScheduleFanOut
Section titled “ScheduleFanOut”Underlying type: string
ScheduleFanOut is who runs a schedule that targets a unit. It maps onto
Crewlet’s schedule target (Each is each, Lead is lead).
Validation:
- Enum: [Each Lead]
Appears in:
| Field | Description |
|---|---|
Each | ScheduleFanOutEach runs one task per agent seat directly in the unit: never the seats of the units below it, and never a Human seat. Each seat runs its own turn, so a slow one never holds up the others. |
Lead | ScheduleFanOutLead runs one task as the unit’s lead: its leadRef, or, unset, the lead it inherits from the units above it. It follows a change of lead without a change to the Schedule. |
ScheduleSpec
Section titled “ScheduleSpec”ScheduleSpec is recurring work a seat or a unit owns: a task the engine
hands its runner on a cron schedule, as a CronJob runs a Job. It renders to
one entry of a Crewlet role’s or unit’s schedules, whose name is the
Schedule’s metadata.name.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
companyRef CompanyReference | companyRef names the Company this schedule belongs to. Immutable. | Required: {} | |
target ScheduleTarget | target is the seat or the unit whose schedule this is. | MinProperties: 1 Required: {} | |
schedule string | schedule is when the task fires: a standard cron expression of five fields (minute, hour, day of month, month, day of week), such as ”30 9 * * 1-5”, evaluated in timeZone. When both the day of month and the day of week are restricted, a day matches if either does. The engine’s dry run checks each field’s values. Crewlet’s cron. | MaxLength: 256 MinLength: 9 Required: {} | |
timeZone string | timeZone is the IANA time zone the schedule is evaluated in, such as Asia/Tokyo. Unset is the Company’s spec.timeZone, which is UTC when that is unset too. The engine refuses a zone it cannot load, and Local, which would be whatever zone the engine’s host is set to. Crewlet’s timezone. | MaxLength: 64 MinLength: 1 Pattern: ^[A-Za-z][A-Za-z0-9_+-]*(/[A-Za-z0-9_+-]+)*$ Optional: {} | |
prompt string | prompt is the task the runner is handed each time the schedule fires, such as “Post your standup: what shipped yesterday, what is next, what blocks you.” Crewlet’s task. | MaxLength: 8192 MinLength: 1 Required: {} | |
suspend boolean | suspend keeps the schedule in the company without firing it. Unset is false. Crewlet’s enabled, inverted. | Optional: {} | |
timeoutSeconds integer | timeoutSeconds caps one scheduled turn’s wall-clock time: a turn past it starts no further round and ends failed. Unset is the engine’s default, 180 seconds. Crewlet’s timeout_seconds. | Minimum: 1 Optional: {} | |
catchUp boolean | catchUp says whether an engine that starts after missing a fire runs the most recent missed one, when it is recent enough (half the schedule’s period, within the engine’s catch-up bounds); older misses are never run. Unset is true. Crewlet’s catchup. | Optional: {} |
ScheduleStatus
Section titled “ScheduleStatus”ScheduleStatus is what the operator observed about a Schedule.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
conditions Condition array | conditions are Accepted (the Company exists), ResolvedRefs (the seat or unit it targets exists, and a seat is an Agent) and Applied (the schedule is in the revision the engine runs). | MaxItems: 8 Optional: {} | |
observedGeneration integer | observedGeneration is the metadata.generation this status describes. | Minimum: 1 Optional: {} |
ScheduleTarget
Section titled “ScheduleTarget”ScheduleTarget is whose recurring work a schedule is: one seat’s, or a unit’s. It decides which entry of the company document the schedule is rendered into: the seat’s role, or the unit’s.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
seatRef LocalObjectReference | seatRef names the Seat, in this namespace, whose schedule this is; it always runs as that seat. The Seat must be an Agent: the engine runs no turn for a person. Rendered into the seat’s role schedules. | Optional: {} | |
unitRef LocalObjectReference | unitRef names the Unit, in this namespace, whose schedule this is; fanOut says who in it runs it. A unit’s schedule is not inherited by the units below it. Rendered into the unit’s schedules. | Optional: {} | |
fanOut ScheduleFanOut | fanOut is who in the unit runs it. Unset is Each. Crewlet’s target.The engine refuses a schedule that could never run while it is not suspended: Each on a unit with no agent seat directly in it, and Lead on a unit whose lead is a Human seat. | Enum: [Each Lead] Optional: {} |
Seat is one seat of a company’s org chart: an AI agent the engine runs, or a person agents work with.
spec.paused pauses an agent seat while keeping it in the chart; Company’s spec.suspend stops the whole engine instead.
Unless spec.handle is set, the Seat’s metadata.name is its handle and must follow the handle’s rules: lowercase letters, digits and ’-’, starting with a letter or digit, at most 63 characters. The handle cannot change.
| Field | Description | Default | Validation |
|---|---|---|---|
apiVersion string | crewlet.ai/v1alpha1 | ||
kind string | Seat | ||
metadata ObjectMeta | Refer to Kubernetes API documentation for fields of metadata. | Optional: {} | |
spec SeatSpec | spec is the seat’s desired state. | Required: {} | |
status SeatStatus | status is the seat’s observed state. | MinProperties: 1 Optional: {} |
SeatContact
Section titled “SeatContact”SeatContact is how agents reach a person: their accounts on the company’s
surfaces, which tie what the person does there to their seat. It maps onto
Crewlet’s role contact, one field for each of its keys but one (below).
Crewlet refuses two seats that claim one account, so a Seat claiming an account another Seat of the company already claims is reported as a Conflict. Each field is compared as Crewlet compares it: githubLogin, gitlabUsername and mattermostUsername without case, as GitHub, GitLab and Mattermost compare them; slackUserID and atlassianAccount exactly.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
slackUserID string | slackUserID is the person’s Slack member id, such as U0123ABCD. Crewlet’s slack_user_id. | MaxLength: 64 MinLength: 1 Pattern: ^[A-Z0-9]+$ Optional: {} | |
mattermostUsername string | mattermostUsername is the person’s username on the company’s Mattermost, such as jane.doe, written without the @: the name an agent mentions them by and opens a direct message with, and the sender an inbound post is attributed by. Crewlet’s mattermost_user_id, which holds the username despite its name, andnever the 26-character user id. Mattermost’s own rule for a username holds it: lowercase letters, digits, ’.’, ’-’ and ’_’, at most 64 characters, and none of the names Mattermost reserves (all, channel, matterbot, system) nor here: a mention of all, channel or here notifies the whole channel rather than the person. | MaxLength: 64 MinLength: 1 Pattern: ^[a-z0-9._-]+$ Optional: {} | |
atlassianAccount string | atlassianAccount is the person’s identity on the company’s Jira and Confluence, one value for both: their account id on Atlassian Cloud, such as 557058:f58131cb-b67d-43c7-b30d-6b58d40bd077 and never their email address, and their username on a Data Center instance, such as jane.doe. Webhooks name the person by it, so it attributes what they do there to their seat, and agents assign and mention them by it. Crewlet’s atlassian_account_id, which holds the username on DataCenter despite its name. Any value up to 255 characters without whitespace is taken, since a Data Center username may hold almost any character. Where the company reaches Jira or Confluence on Atlassian Cloud, a value outside the form of an account id (letters, digits, ’_’, ’|’, ’:’ and ’-’, at most 128 characters) is applied and reported on the Seat as ResolvedRefs=False with the reason NotAnAccountID. | MaxLength: 255 MinLength: 1 Pattern: ^\S+$ Optional: {} | |
githubLogin string | githubLogin is the person’s GitHub login. Crewlet’s github_login. | MaxLength: 39 MinLength: 1 Pattern: ^[A-Za-z0-9-]+$ Optional: {} | |
gitlabUsername string | gitlabUsername is the person’s GitLab username, written without the @: assignments, review requests, mentions, and the sender an inbound webhook is attributed by. Crewlet’s gitlab_username. GitLab’s ownrule for a username’s form holds it: letters, digits, ’_’, ’-’ and ’.’, at most 255 characters, not starting with ’-’ and not ending with ’.’. | MaxLength: 255 MinLength: 1 Pattern: ^([A-Za-z0-9_.][A-Za-z0-9_.-]*[A-Za-z0-9_-]|[A-Za-z0-9_])$ Optional: {} |
SeatCredentialSource
Section titled “SeatCredentialSource”SeatCredentialSource says where one of a seat’s own credentials comes from: a Secret key, or the engine, which provisions it (see ProvisionedCredential).
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
secretKeyRef SecretKeyReference | secretKeyRef selects the Secret key that holds the value. | Optional: {} | |
provisioned ProvisionedCredential | provisioned is a value the engine creates and keeps, under an Integration with provisioning Engine. | Optional: {} |
SeatEnvVar
Section titled “SeatEnvVar”SeatEnvVar is a named credential of a seat delivered as an environment variable: from a Secret, or provisioned by the engine.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name is the variable’s name. | MaxLength: 128 MinLength: 1 Pattern: ^[A-Za-z_][A-Za-z0-9_]*$ Required: {} | |
valueFrom SeatCredentialSource | valueFrom is where the value comes from. | MinProperties: 1 Required: {} |
SeatIntegrations
Section titled “SeatIntegrations”SeatIntegrations is a seat’s own identity on the company’s integrations: the chat app it speaks as, the code-host app it acts as. Its tool credentials, the GitLab, Jira, Confluence and Datadog ones included, are in spec.mcp instead, which is where Crewlet reads them.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
slack SlackSeatIntegration | slack is the seat’s own Slack app. | Optional: {} | |
github GitHubSeatIntegration | github is the seat’s identity on GitHub. | MinProperties: 1 Optional: {} | |
mattermost MattermostSeatIntegration | mattermost is the seat’s own Mattermost bot. | Optional: {} |
SeatIntegrationsStatus
Section titled “SeatIntegrationsStatus”SeatIntegrationsStatus is the addresses a seat’s vendor apps must use.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
slack SlackSeatStatus | slack is the Slack side of the seat. | MinProperties: 1 Optional: {} | |
github GitHubSeatStatus | github is the GitHub side of the seat. | MinProperties: 1 Optional: {} |
SeatKind
Section titled “SeatKind”Underlying type: string
SeatKind is whether a seat is an AI agent or a person. It maps onto
Crewlet’s role kind (Agent is agent, Human is human).
Validation:
- Enum: [Agent Human]
Appears in:
| Field | Description |
|---|---|
Agent | SeatKindAgent is an AI agent: the engine runs it, with its own inbox, models and tools. |
Human | SeatKindHuman is a person: part of the chart (a lead, an escalation target, a colleague to mention) whom the engine never runs. |
SeatLLM
Section titled “SeatLLM”SeatLLM is the model providers a seat runs on, one fallback chain per phase
of its work: when every key of the first provider is cooling down, the next
is tried. It maps onto Crewlet’s per-phase llm mapping. A phase left unset
uses the default chain; a seat with no default chain runs on the first
provider of the Company’s spec.llm.order alone, with no fallback.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
default LLMProviderReference array | default is the chain of every phase not set below, including the executor that does the seat’s work. Crewlet’s default. | MaxItems: 8 MinItems: 1 Optional: {} | |
review LLMProviderReference array | review is the chain of the reviewer that judges the executor’s work. Crewlet’s review. | MaxItems: 8 MinItems: 1 Optional: {} | |
subagent LLMProviderReference array | subagent is the chain of the short-lived workers the seat delegates to. Crewlet’s subagent. | MaxItems: 8 MinItems: 1 Optional: {} | |
auxiliary LLMProviderReference array | auxiliary is the chain of the cheap model used for reflection and summaries. Crewlet’s auxiliary. | MaxItems: 8 MinItems: 1 Optional: {} | |
judge LLMProviderReference array | judge is the chain of the model that decides whether a turn that ran out of rounds may have more. Crewlet’s judge. | MaxItems: 8 MinItems: 1 Optional: {} | |
sandbox LLMProviderReference array | sandbox is the chain the coding agent in the seat’s sandbox runs on. Unset takes default, then the Company’s model order. A coding run uses the chain’s head alone, as its model and its sign-in, so the head must be a provider the coding agent can read: an Anthropic provider, or for OpenCode an OpenAI or OpenAICompatible one too, or a CLIAgent provider of the coding agent’s own CLI. The operator refuses a CLIAgent provider of another CLI (CodingAgentMismatch), and reports any other head the coding agent cannot run on in the CodeWorkRunnable condition. Every box of the seat carries the head’s first API key, and under ClaudeCode its baseURL, unless spec.sandbox.env signs ClaudeCode in itself: give code work a provider whose key is scoped for it. A seat whose executor runs in agent mode (a CLIAgent provider in mode Agent heads its executor’s chain: default, else the Company’s spec.llm.order) has no code work of its own, so nothing reads this chain for one. Crewlet’s sandbox. | MaxItems: 8 MinItems: 1 Optional: {} |
SeatPauseStatus
Section titled “SeatPauseStatus”SeatPauseStatus is a seat’s pause, as the engine reports it.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
pausedBy string | pausedBy is who paused the seat, as Crewlet records the author of a write: the seat of the person who paused it, or token: token no seat is bound to. A pause the operator took reads token:operator. | MaxLength: 256 MinLength: 1 Optional: {} | |
pausedAt Time | pausedAt is when the seat was paused, to the second. | Optional: {} | |
reason string | reason is why, in the pauser’s words. | MaxLength: 500 MinLength: 1 Optional: {} | |
stopRunning boolean | stopRunning is whether the pause also ended the turn the seat was on. | Optional: {} |
SeatPlacement
Section titled “SeatPlacement”SeatPlacement is where a seat runs.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
pool string | pool is the pool of pods that runs the seat: data, the company’s data pods, or the name of one of the Company’s spec.topology.seatPools. The seat is pinned to the pool with Crewlet’s role.placement, which the engine never widens: while the pool runs no pod, the seat runs nowhere and its messages wait for one. | MaxLength: 20 MinLength: 1 Pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ Required: {} |
SeatPlacementStatus
Section titled “SeatPlacementStatus”SeatPlacementStatus is where the engine runs a seat.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
pool string | pool is the pool of pods that runs the seat: spec.placement.pool, or the Company’s spec.topology.defaultSeatPool. The seat is rendered with role.placement.labels {crewlet.ai/pool: pods carry, or, in a PerSeat pool, {crewlet.ai/seat: only the seat’s own pods carry. | MaxLength: 20 MinLength: 1 Optional: {} | |
workload string | workload is the name of the StatefulSet whose pods may run the seat: the data pods’, the Shared pool’s, or the seat’s own in a PerSeat pool. | MaxLength: 63 MinLength: 1 Optional: {} | |
node string | node is the engine node, a pod’s name, that holds the seat’s lease and runs it, as the engine’s GET /fleet last reported. Unset while no node holds it. | MaxLength: 64 MinLength: 1 Optional: {} |
SeatPool
Section titled “SeatPool”SeatPool is a set of stateless pods that run seats: they hold no data, join the company’s event stream through the data pods, and keep a scratch store they delete at every start. A seat runs in it when its Seat’s spec.placement.pool names it, or when it is the Company’s defaultSeatPool and the Seat names no pool. The class’s spec.seatPools.policy must be Allowed.
The operator runs a Shared pool as the StatefulSet
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name identifies the pool: a DNS label of at most 20 characters, other than data, which is the data pods’ pool. It names the pool’s pods and is the value of the crewlet.ai/pool label a Shared pool’s seats are pinned to. | MaxLength: 20 MinLength: 1 Pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ Required: {} | |
mode SeatPoolMode | mode is how the pool runs its seats. | Shared | Enum: [Shared PerSeat] Optional: {} |
replicas integer | replicas is, for a Shared pool, how many pods it runs, 0 to 100: at 0 its seats run nowhere, and their messages wait for a pod. For a PerSeat pool it is how many pods it runs for each of its seats, 1 or 2. | 1 | Maximum: 100 Minimum: 0 Optional: {} |
maxConcurrentTurns integer | maxConcurrentTurns is how many turns one of the pool’s pods runs at once: Crewlet’s node.max_concurrent. Unset takes the class’s seatPools.defaults. | Minimum: 1 Optional: {} | |
terminationGracePeriodSeconds integer | terminationGracePeriodSeconds is how long one of the pool’s pods may take to stop, finishing its running turns: the engine puts no bound of its own on that drain, so it must cover the longest turn. Unset takes the class’s seatPools.defaults, else 300. | Maximum: 3600 Minimum: 30 Optional: {} |
SeatPoolDefaults
Section titled “SeatPoolDefaults”SeatPoolDefaults sizes the pods of a seat pool that does not size its own, and the compute of every seat pod, which the class alone sets: a Company’s pools choose how many pods they run, within maxPods, and the class what each of them may take, as it does for the data pods.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
maxConcurrentTurns integer | maxConcurrentTurns is how many turns one seat pod runs at once: Crewlet’s node.max_concurrent. Unset takes the engine’s default, 32. A seat runs one turn at a time, so a pod never runs more turns at once than it holds seats. | Minimum: 1 Optional: {} | |
resources ResourceRequirements | resources are the compute resources of every seat pod’s engine container. Unset sets none. | Optional: {} | |
terminationGracePeriodSeconds integer | terminationGracePeriodSeconds is how long a seat pod may take to stop. A seat pod finishes its running turns before it exits, with no bound of its own, so unset is five minutes, as for a data pod, rather than the Kubernetes default of thirty seconds. | Maximum: 3600 Minimum: 30 Optional: {} | |
scratchSizeLimit Quantity | scratchSizeLimit caps the emptyDir a seat pod keeps its scratch store in: a store the engine deletes at every start, its native library (about 20 MB, extracted at every start) and the files of the processes it runs (stdio MCP servers, git). A pod that writes more is evicted. Unset is 2Gi. | Optional: {} |
SeatPoolMode
Section titled “SeatPoolMode”Underlying type: string
SeatPoolMode is how a seat pool runs the seats placed in it.
Validation:
- Enum: [Shared PerSeat]
Appears in:
| Field | Description |
|---|---|
Shared | SeatPoolShared runs replicas pods that share the pool’s seats between them: each takes an even share, and a pod that stops hands its seats to the others. |
PerSeat | SeatPoolPerSeat runs replicas pods for each seat placed in the pool, each holding that seat alone. It needs the class’s seatPools.allowPerSeat. |
SeatPoolPolicy
Section titled “SeatPoolPolicy”Underlying type: string
SeatPoolPolicy is whether a class’s companies may run seats on pods of their own, outside the data pods.
Validation:
- Enum: [Forbidden Allowed]
Appears in:
| Field | Description |
|---|---|
Forbidden | SeatPoolsForbidden runs every seat on the data pods. A Company of the class may declare no spec.topology.seatPools. |
Allowed | SeatPoolsAllowed lets a Company declare seat pools, and opens the leaf listener its seat pods join the company’s event stream through on every data pod of the class, from the data pod’s first start, so that a company adding its first pool restarts nothing. |
SeatPoolSettings
Section titled “SeatPoolSettings”SeatPoolSettings is whether, and how far, a class’s companies may run seats on stateless pods of their own (a Company’s spec.topology.seatPools). A seat pod holds no data: it joins the company’s event stream as a NATS leaf of the data pods, keeps a scratch store it deletes at every start, and runs the seats placed in its pool.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
policy SeatPoolPolicy | policy is whether the class’s companies may declare seat pools. Changing it restarts every data pod of the class, which opens or closes the leaf listener. | Forbidden | Enum: [Forbidden Allowed] Optional: {} |
allowPerSeat boolean | allowPerSeat lets a Company declare a PerSeat pool, which runs one pod (or two, a warm standby) for each seat placed in it. Each costs a pod, and every pod’s work grows with the number of seats of the company, so it is off by default and meant for the few seats that need a pod to themselves. It isolates a seat’s compute and its failures, not its credentials: every pod of a company can read the company’s whole secret store. | Optional: {} | |
maxPods integer | maxPods is the most seat pods a Company of the class may run, all of its pools together: each Shared pool’s replicas, and each PerSeat pool’s replicas for every seat placed in it. The data pods are not counted. Required with policy Allowed: a class’s companies size their own pools, and only this bounds how many seat pods a company of the class runs. | Minimum: 1 Optional: {} | |
defaults SeatPoolDefaults | defaults size the pods of a pool that does not size its own. | MinProperties: 1 Optional: {} |
SeatPoolStatus
Section titled “SeatPoolStatus”SeatPoolStatus is the state of one seat pool’s pods.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name is the pool’s name. | MaxLength: 20 MinLength: 1 Required: {} | |
mode SeatPoolMode | mode is how the pool runs its seats. | Enum: [Shared PerSeat] Optional: {} | |
replicas integer | replicas is the number of the pool’s pods, every seat’s together for a PerSeat pool. | Minimum: 0 Optional: {} | |
readyReplicas integer | readyReplicas is the number of the pool’s pods that are ready. | Minimum: 0 Optional: {} | |
updatedReplicas integer | updatedReplicas is the number of the pool’s pods that run the current pod template. | Minimum: 0 Optional: {} | |
seats integer | seats is the number of agent seats placed in the pool. | Minimum: 0 Optional: {} |
SeatSandbox
Section titled “SeatSandbox”SeatSandbox gives a seat a sandbox to run code in, on the Company’s
spec.sandbox. It maps onto Crewlet’s role sandbox; its presence is
Crewlet’s enabled: true.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
codingAgent CodingAgent | codingAgent is the coding agent the seat’s sandbox runs. Unset takes the Company’s spec.sandbox.defaultCodingAgent. ClaudeCode runs on an Anthropic provider or a ClaudeCode CLIAgent one, unless the seat’s sandbox environment signs it in itself; OpenCode runs on an Anthropic, OpenAI or OpenAICompatible provider or an OpenCode CLIAgent one. A seat whose executor runs in agent mode (a CLIAgent provider in mode Agent heads its executor’s chain) is never offered run_sandbox: it codes in its executor’s run, on that provider’s CLI, so this drives nothing, and the operator refuses one other than that CLI (CodingAgentMismatch), as Crewlet does. Crewlet’s coding_agent. | Enum: [ClaudeCode OpenCode] Optional: {} | |
pauseTTLSeconds integer | pauseTTLSeconds is how long the seat’s sandbox stays paused while it waits on a person. Unset takes the Company’s default; 0 never pauses. Crewlet’s pause_ttl_seconds. | Minimum: 0 Optional: {} | |
maxTurns integer | maxTurns caps the agentic rounds of the seat’s coding runs. Unset takes the Company’s default; 0 is uncapped. Crewlet’s max_turns. | Minimum: 0 Optional: {} | |
mcpServerRefs LocalObjectReference array | mcpServerRefs name the MCPServers the coding agent may use. Crewlet’s mcp.servers. | MaxItems: 16 Optional: {} | |
env SeatEnvVar array | env is the environment of the seat’s sandbox runs, for the external tokens its code work needs: from Secrets, or provisioned by the engine, such as the GitLab token a provisioning Integration mints for the seat, named as its tool server’s is so both are one token. A ClaudeCode sign-in here (CLAUDE_CODE_OAUTH_TOKEN, ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN or a CLAUDE_CODE_USE_* toggle) keeps the key and endpoint of the provider the code work runs on out of the box, unless a run goes without its value (optionalKeys), when the box is given them as it is with no sign-in; and a variable named as one the provider would set wins over it. Crewlet’s env, a credentialposition. | MaxItems: 32 Optional: {} | |
optionalKeys string array | optionalKeys names variables of env whose value may go missing. Crewlet refuses to start a run_sandbox coding run whose environment holds a value that does not resolve: a Secret that does not exist, holds no such key or holds an empty value, or a provisioned value nothing mints. Under a variable listed here, such a value is left out of the run instead, which starts without it. A missing Secret or key under one is then no failure of the Seat’s references and holds nothing back. Under the Enforce policy the operator also takes the value it pushed for it out of the engine’s secret store, and has the engine read the store again whether or not the document can be applied, so no run starts with a deleted Secret’s value, but in a revision the engine runs that reads the key as required (one from before the key was listed) or whose reading the operator does not know (another document somebody else activated), which keeps the value until the next document runs, and that one is activated once with it and at once again without it; a Secret key that is also read where it is required holds the document while it is missing, and keeps the value it had in a revision the engine runs that requires it too until the document applies. A provisioned value an Integration mints for the seat is waited for whatever this says. env wins over a setup step’s variable of the same name, and so does this list over the step’s optionalKeys for it. Crewlet’s optional_keys. | MaxItems: 32 items:MaxLength: 128 items:MinLength: 1 items:Pattern: ^[A-Za-z_][A-Za-z0-9_]*$ Optional: {} | |
setup SandboxSetupStep array | setup is the seat’s own provisioning, applied after the Company’s. Crewlet’s setup. | MaxItems: 16 Optional: {} |
SeatSpec
Section titled “SeatSpec”SeatSpec is one seat of a company: an AI agent or a person. It renders to one entry of Crewlet’s roles, nested under its unit’s.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
companyRef CompanyReference | companyRef names the Company this seat belongs to. Immutable. | Required: {} | |
handle string | handle is the seat’s canonical slug. Unset is the Seat’s metadata.name. Crewlet derives the seat’s identity, and with it the seat’s memory, from the company name and the handle, so the handle cannot be changed; a Seat deleted and created again with the same handle gets its memory back. Crewlet’s handle. | MaxLength: 63 MinLength: 1 Pattern: ^[a-z0-9][a-z0-9-]*$ Optional: {} | |
kind SeatKind | kind is whether the seat is an AI agent or a person. Crewlet’s kind. | Agent | Enum: [Agent Human] Optional: {} |
displayName string | displayName is the seat’s name as people read it, such as “Ana (Platform Engineer)”. Unset is the handle. Crewlet’s name. It is forreading only: one seat names another, a unit its lead and a seat what it manages, by the handle, so two Seats may share a displayName. | MaxLength: 256 MinLength: 1 Optional: {} | |
email string | email is the seat’s email address. Crewlet’s email. Each seat has itsown: the engine finds a seat by its address, compared lower-cased and with any plus tag dropped, so a Seat whose address another Seat’s matches that way is reported as a Conflict. | MaxLength: 254 MinLength: 3 Pattern: ^[^@\s]+@[^@\s]+$ Optional: {} | |
unitRef LocalObjectReference | unitRef names the Unit, in this namespace, the seat belongs to. Unset is a seat outside every unit, such as a chief executive. | Optional: {} | |
goal string | goal is what the seat is for; it reaches the seat’s prompt. Crewlet’sgoal. | MaxLength: 2048 MinLength: 1 Optional: {} | |
backstory string | backstory is who the seat is; it reaches the seat’s prompt. Crewlet’sbackstory. | MaxLength: 8192 MinLength: 1 Optional: {} | |
responsibilities string array | responsibilities are what the seat owns. Crewlet’sresponsibilities. | MaxItems: 32 items:MaxLength: 1024 items:MinLength: 1 Optional: {} | |
behavioralGuidelines string array | behavioralGuidelines are how the seat should work. Crewlet’sbehavioral_guidelines. | MaxItems: 32 items:MaxLength: 1024 items:MinLength: 1 Optional: {} | |
manages ManagedReference array | manages names the seats and units this seat manages; a unit stands for every seat in it and below it. Crewlet’s manages, which names aSeat by its handle and a Unit by its metadata.name, the Unit’s key; a key that is also a seat’s handle reads as the seat, so a Unit named so is refused here as a Conflict. | MaxItems: 64 Optional: {} | |
workers string array | workers narrows which of the company’s delegate templates (the workers block of the Company’s engineConfig) the seat may use, by the templates’ names: a lowercase letter or digit, then lowercase letters, digits, ’_’ and ’-’. Unset is every one. Crewlet’s workers. | MaxItems: 32 items:MaxLength: 128 items:MinLength: 1 items:Pattern: ^[a-z0-9][a-z0-9_-]*$ Optional: {} | |
tokenBudget TokenBudget | tokenBudget caps the tokens this seat may spend per window, on top of the Company’s caps. Crewlet’s token_budget. | MinProperties: 1 Optional: {} | |
llm SeatLLM | llm is the model providers the seat runs on. | MinProperties: 1 Optional: {} | |
learningEnabled boolean | learningEnabled overrides the company’s learning setting for this seat: false stops reflection after the seat’s turns. Unset inherits. Crewlet’s learning_enabled. | Optional: {} | |
mcp MCPCredentials array | mcp are the seat’s own tool-server credentials, which make it act as itself on each server, and its own settings, such as the channel cache of slack-mcp-server, which no other seat may share. They are merged over its unit’s, per variable. One entry per server, keyed by its name. Crewlet’s mcp_env, a credential position. | MaxItems: 16 Optional: {} | |
sandbox SeatSandbox | sandbox gives the seat a sandbox to run code in. Unset gives it none. | Optional: {} | |
placement SeatPlacement | placement is where the seat runs. Unset runs it in the Company’s spec.topology.defaultSeatPool. | Optional: {} | |
paused boolean | paused says whether the seat may take work. True pauses it: it starts no new turn, the mail it is sent waits on its inbox in order, and its schedules’ fires are skipped rather than queued; the turn it is on finishes first unless stopRunning is set. False resumes it, and what waited is delivered first. Unset leaves the seat’s pause to the people who run the company in the engine’s dashboard: the operator reports a pause they take, and never lifts it. A pause is not part of the company document. Crewlet keeps it in its coordination store, changed through its operator catalogue’s pause_seat and resume_seat tools, which the operator calls under the Company’s Enforce policy whenever the seat’s pause differs from this field; under Observe and Seed it only reports the difference. | Optional: {} | |
pauseReason string | pauseReason is why the seat is paused, shown on the seat and in its feed in the engine. Only with paused true. The engine keeps the reason a pause was taken with, so a reason changed while the seat stays paused shows from the seat’s next pause on. Crewlet’s pause reason. | MaxLength: 500 MinLength: 1 Optional: {} | |
stopRunning boolean | stopRunning ends the turn the seat is on at its next round when it is paused, rather than letting the turn finish; the stopped turn is not run again. Only with paused true. Setting it on a seat already paused stops the turn it is on then; unsetting it changes nothing, since a stopped turn stays stopped. Crewlet’s pause stop_running. | Optional: {} | |
integrations SeatIntegrations | integrations is the seat’s own identity on the company’s integrations. | MinProperties: 1 Optional: {} | |
project string | project is the tracker project a seat outside every unit owns, by its key; a seat in a unit takes its unit’s. Crewlet requires a container key to be an upper-case letter followed by 1 to 9 upper-case letters or digits, such as LEAD. Crewlet’s project. | MaxLength: 10 MinLength: 2 Pattern: ^[A-Z][A-Z0-9]\{1,9\}$ Optional: {} | |
space string | space is the knowledge container a seat outside every unit owns, by its key, which follows the same rule as project; a seat in a unit takes its unit’s. Crewlet’s space. | MaxLength: 10 MinLength: 2 Pattern: ^[A-Z][A-Z0-9]\{1,9\}$ Optional: {} | |
contact SeatContact | contact is how agents reach the person in a Human seat on a chat surface, and how what the person does there reaches the engine as theirs. It applies to Human seats only, and is optional: a person who works only through the engine’s dashboard has no account to name, and signs in on the seat through the engine’s own identity directory. The engine warns of a Human seat without one, since nothing addressed to it on a chat surface reaches anybody, and the operator records the warning as an EngineWarnings event on the Company. | MinProperties: 1 Optional: {} | |
availability string | availability tells colleagues of a Human seat when to expect an answer, such as “CET business hours”. Crewlet’s availability. | MaxLength: 256 MinLength: 1 Optional: {} |
SeatStatus
Section titled “SeatStatus”SeatStatus is what the operator observed about a Seat.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
conditions Condition array | conditions are Accepted (the Company exists, and no other Seat has the handle, the email or a contact account; Conflict names the other), ResolvedRefs (the unit, the providers, the tool servers and every Secret key exist), Applied (the seat is in the revision the engine runs) and, on an Agent seat, Ready (an engine node holds the seat’s lease and runs it: LeaseHeld, or Unplaced, or PoolNotFound; or the seat can run no turn wherever it is held, AgentModeBridgeUnsupported or NotExposed) and, once the engine runs it, Paused (whether the engine holds it paused, and whether that is what spec.paused asks), and, on an Agent seat with spec.sandbox whose executor does not run in agent mode, in a Company with spec.sandbox, CodeWorkRunnable (whether its coding agent can run on the head of its sandbox chain or on the sign-in the seat’s sandbox environment gives it; it does not count towards Ready, as the seat runs its turns either way). | MaxItems: 8 Optional: {} | |
observedGeneration integer | observedGeneration is the metadata.generation this status describes. | Minimum: 1 Optional: {} | |
handle string | handle is the seat’s handle: spec.handle, or the metadata.name. | MaxLength: 63 MinLength: 1 Optional: {} | |
seatID string | seatID is the seat’s identity in the engine, derived from the company name and the handle, so that callers need not derive it themselves. Unset for a Human seat, which the engine does not run and gives no identity, and for a seat whose handle another Seat derives too. | MaxLength: 36 MinLength: 36 Optional: {} | |
placement SeatPlacementStatus | placement is where the engine runs the seat. Unset for a Human seat, which the engine does not run. | MinProperties: 1 Optional: {} | |
integrations SeatIntegrationsStatus | integrations is the addresses the seat’s vendor apps must use. Unset for a Human seat, which has no vendor apps of its own. | MinProperties: 1 Optional: {} | |
pause SeatPauseStatus | pause is the seat’s pause while the engine holds it paused, whoever paused it: the operator, for spec.paused, or a person in the engine’s dashboard. Unset while the seat takes work. | MinProperties: 1 Optional: {} |
SecondFactor
Section titled “SecondFactor”Underlying type: string
SecondFactor is whether a person signing in to a company’s dashboard with a
password must also prove a second factor. It maps onto Crewlet’s
api.auth.totp (Required is required, Optional is optional).
Validation:
- Enum: [Required Optional]
Appears in:
| Field | Description |
|---|---|
Required | SecondFactorRequired has everyone who signs in with a password also give a code from an authenticator app, or one of their recovery codes, and has a person without one set it up at their first sign-in, before anything else. It is Crewlet’s default. |
Optional | SecondFactorOptional lets a person sign in with a password alone. A person may still set up an authenticator app, and is then asked for its code like everyone under Required; nobody is made to. |
SecretEnvVar
Section titled “SecretEnvVar”SecretEnvVar is a named credential delivered as an environment variable, such as a sandbox setup step’s token or a coding CLI’s model key. Crewlet treats every value in the positions that use this type as a credential, so a literal value is not accepted: the value always comes from a Secret.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name is the variable’s name. | MaxLength: 128 MinLength: 1 Pattern: ^[A-Za-z_][A-Za-z0-9_]*$ Required: {} | |
valueFrom SecretValueSource | valueFrom is the Secret key the value is read from. | Required: {} |
SecretKeyReference
Section titled “SecretKeyReference”SecretKeyReference selects one key of a Secret in the referring object’s namespace. The operator reads the value when it renders the company and pushes it into the engine’s encrypted secret store; the value itself never appears in the company document, in a pod template or in any status.
Appears in:
- AtlassianIntegration
- CLIAgentAuth
- ConfluenceIntegration
- DatadogIntegration
- E2BSandbox
- EmbeddingSettings
- GitHubIntegration
- GitLabEngineProvisioning
- GitLabIntegration
- JiraIntegration
- LLMProviderSpec
- MattermostEngineProvisioning
- SeatCredentialSource
- SecretValueSource
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name is the metadata.name of the Secret. | MaxLength: 253 MinLength: 1 Required: {} | |
key string | key is the key within the Secret’s data. | MaxLength: 253 MinLength: 1 Pattern: ^[-._a-zA-Z0-9]+$ Required: {} |
SecretReference
Section titled “SecretReference”SecretReference names a whole Secret in the referring object’s namespace. It is used where one credential is several values that are always issued together (a Slack app’s bot token and signing secret, for example); the field that holds the reference documents the keys the Secret must carry.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
name string | name is the metadata.name of the Secret. | MaxLength: 253 MinLength: 1 Required: {} |
SecretValueSource
Section titled “SecretValueSource”SecretValueSource says where a credential’s value comes from. It has one member today; it is a struct so that a second source can be added without reshaping every list that carries credentials.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
secretKeyRef SecretKeyReference | secretKeyRef selects the Secret key that holds the value. | Required: {} |
SignInSettings
Section titled “SignInSettings”SignInSettings is how people prove who they are when they sign in to the dashboards of a class’s companies.
It is the class’s, not the Company’s, because it weakens how people prove who they are, which is the platform’s decision: a tenant could otherwise lower it for every person of its company, and the people who sign in are often not the people who write the Company. A platform offers it the way it offers exposure.trustedProxies, on a class it writes for the companies that may run with it (a test rig, a demo tier).
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
secondFactor SecondFactor | secondFactor is whether a person who signs in with a password must also give a code from an authenticator app (Required), or may sign in with the password alone (Optional). Crewlet’s api.auth.totp. Optional is refused by Crewlet on an address a browser reaches over the network unless acceptInsecure acknowledges it, and the engine judges that by where it is told people reach it, the Company’s status.endpoints.dashboardBaseURL: a host of localhost (in any case) or a loopback IP, such as the http://localhost:8080 of a company reached through kubectl port-forward, needs no acknowledgement, and any other host does. A company of the class whose address needs one it does not have keeps its engine’s pods as they are, with RuntimeReady=False InsecureSignInNotAcknowledged, rather than start an engine that refuses to boot. The engine reads it only at start, so a change to Optional or back restarts each company’s data pod. | Required | Enum: [Required Optional] Optional: {} |
acceptInsecure boolean | acceptInsecure acknowledges that a company of the class lets people sign in with a password alone on an address a browser reaches over the network: it is what lets secondFactor Optional run there, and applies to secondFactor Optional only. It lifts nothing else, plain http on such an address included, which the engine warns of either way. While it is set the engine logs a config_advisory line at WARN at every start, saying the insecure sign-in settings are allowed at its address, for as long as the class sets it. Crewlet’s api.auth.accept_insecure. | Optional: {} |
SlackIntegration
Section titled “SlackIntegration”SlackIntegration turns Slack on for a company. It maps onto Crewlet’s integrations.slack. Slack has no company-wide credential: every agent seat that speaks on Slack has its own app, in its Seat’s spec.integrations.slack.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
typingStatus WorkingStatus | typingStatus is when a seat shows that it is working. Unset takes Crewlet’s default, Always. Crewlet’s typing_status. | Enum: [Always Addressed] Optional: {} | |
statusPhrases StatusPhrases | statusPhrases replaces the words the working indicator shows. Crewlet’s status_phrases. | MinProperties: 1 Optional: {} |
SlackSeatIntegration
Section titled “SlackSeatIntegration”SlackSeatIntegration is a seat’s own Slack app, so the seat posts as itself. It maps onto Crewlet’s role integrations.slack and needs the company’s Slack Integration.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
credentialsSecretRef SecretReference | credentialsSecretRef is a Secret holding the app’s credentials under the keys botToken (the bot token) and signingSecret (which verifies the app’s webhooks). Crewlet’s bot_token and signing_secret, bothcredential positions. Rewriting the Secret rotates them without a restart. | Required: {} |
SlackSeatStatus
Section titled “SlackSeatStatus”SlackSeatStatus is the Slack side of a seat, as the operator computed it.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
requestURL string | requestURL is the URL the seat’s Slack app must deliver events to: its Event Subscriptions request URL, where publicBaseURL is the Company’s status.endpoints.publicBaseURL. It is set whenever the Company has a Slack Integration and a public base URL, whether or not this Seat sets spec.integrations.slack: a platform that creates the seat’s Slack app needs the URL for the app’s manifest before the app, and so its credentials, exist. Derived from the handle, which never changes, it never changes for a seat either. | MaxLength: 2048 MinLength: 1 Optional: {} |
StatusPhrases
Section titled “StatusPhrases”StatusPhrases replaces the words a seat’s working indicator shows. Each line
completes the sentence ”
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
onboarding string array | onboarding is shown during a seat’s first-turn onboarding pass. | MaxItems: 32 items:MaxLength: 256 items:MinLength: 1 Optional: {} | |
execute string array | execute is shown while the seat works. | MaxItems: 32 items:MaxLength: 256 items:MinLength: 1 Optional: {} | |
review string array | review is shown while the reviewer judges the seat’s work. | MaxItems: 32 items:MaxLength: 256 items:MinLength: 1 Optional: {} | |
default string array | default is shown in any phase without lines of its own. | MaxItems: 32 items:MaxLength: 256 items:MinLength: 1 Optional: {} |
StreamMode
Section titled “StreamMode”Underlying type: string
StreamMode is where a company’s event stream runs.
Validation:
- Enum: [Embedded]
Appears in:
| Field | Description |
|---|---|
Embedded | StreamModeEmbedded runs NATS JetStream inside the engine process, with its data on the data volume. An external NATS cluster is not offered in v1alpha1. |
StreamSettings
Section titled “StreamSettings”StreamSettings is how a company’s event stream runs.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
mode StreamMode | mode is where the stream runs. Embedded is the only mode in v1alpha1. | Embedded | Enum: [Embedded] Optional: {} |
TelemetrySettings
Section titled “TelemetrySettings”TelemetrySettings sends the engine’s traces and metrics to an OpenTelemetry collector. The engine reads its exporter configuration from the standard OTEL_* environment variables, which the operator sets from these fields; with an endpoint set, Crewlet exports metrics as well as traces, and the two cannot be turned off separately (OTEL_ names are the operator’s, so OTEL_METRICS_EXPORTER cannot be set in env). While a Company has a public address (status.endpoints.publicBaseURL), the operator also wires Crewlet’s sandbox telemetry receiver there (CREWLET_SANDBOX_OTEL_RECEIVER_URL): code a remote sandbox runs exports to the engine’s public listener with a token signed for its one run, and the engine forwards it to this collector with the headers below, which never enter the sandbox.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
otlpEndpoint string | otlpEndpoint is the collector’s OTLP/HTTP endpoint (OTEL_EXPORTER_OTLP_ENDPOINT). | MaxLength: 2048 MinLength: 1 Required: {} | |
headersSecretRef NamespacedSecretKeyReference | headersSecretRef is a Secret key holding the headers sent to the collector, in the OTEL_EXPORTER_OTLP_HEADERS format (key1=value1,key2=value2), usually to authenticate. The operator copies the value into a Secret it owns in each Company’s namespace and references it from the pod; the value never appears in the pod template. It is in the engine’s environment, which code the tenant runs in the pod can read, so it reaches every tenant of the class: use a credential that may only write telemetry, scoped per tenant where the collector allows it. | Optional: {} |
TokenBudget
Section titled “TokenBudget”TokenBudget caps how many LLM tokens may be spent per calendar window on the company’s clock (spec.timeZone of the Company). Every window is optional and independent; an absent window is uncapped. It maps onto Crewlet’s token_budget block.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
day integer | day is the most tokens one local day, midnight to midnight, may spend. | Minimum: 1 Optional: {} | |
week integer | week is the most tokens one ISO week, starting on Monday, may spend. | Minimum: 1 Optional: {} | |
month integer | month is the most tokens one calendar month may spend. | Minimum: 1 Optional: {} |
TopologyStatus
Section titled “TopologyStatus”TopologyStatus is the state of a company’s pods.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
data DataTopologyStatus | data is the state of the data pods. | MinProperties: 1 Optional: {} | |
seatPools SeatPoolStatus array | seatPools is the state of each seat pool’s pods. | MaxItems: 8 Optional: {} |
TrackerBackend
Section titled “TrackerBackend”Underlying type: string
TrackerBackend is which work tracker a company runs. It maps onto Crewlet’s
tracker.backend (Native is native, Jira is jira, None is none).
Validation:
- Enum: [Native Jira None]
Appears in:
| Field | Description |
|---|---|
Native | TrackerNative is the engine’s own tracker. |
Jira | TrackerJira is Jira, connected by the company’s Jira Integration. |
None | TrackerNone is a company with no tracker. |
TrackerSettings
Section titled “TrackerSettings”TrackerSettings is which work tracker a company runs. It maps onto Crewlet’s tracker block.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
backend TrackerBackend | backend is which tracker the company runs. | Native | Enum: [Native Jira None] Optional: {} |
native NativeTrackerSettings | native is the policy of the engine’s own tracker, for backend Native. | MinProperties: 1 Optional: {} |
Unit is one node of a company’s org chart. Units nest through spec.parentRef; Seats join one through spec.unitRef.
The Unit’s metadata.name is the unit’s stable id in Crewlet, which has its own rules: it must start with a lowercase letter and be at most 64 characters, and may hold lowercase letters, digits and ’-’. (Crewlet also admits ’_’ in a unit id, which no Kubernetes name can hold.)
| Field | Description | Default | Validation |
|---|---|---|---|
apiVersion string | crewlet.ai/v1alpha1 | ||
kind string | Unit | ||
metadata ObjectMeta | Refer to Kubernetes API documentation for fields of metadata. | Optional: {} | |
spec UnitSpec | spec is the unit’s desired state. | Required: {} | |
status UnitStatus | status is the unit’s observed state. | MinProperties: 1 Optional: {} |
UnitSpec
Section titled “UnitSpec”UnitSpec is one node of a company’s org chart: a division, a team, a squad. It renders to one entry of Crewlet’s units, nested under its parent’s.
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
companyRef CompanyReference | companyRef names the Company this unit belongs to. Immutable. | Required: {} | |
displayName string | displayName is the unit’s name as people read it, in prompts and on boards. Unset is the Unit’s metadata.name. The metadata.name itself is the unit’s stable id, which survives a rename. Crewlet’s name; themetadata.name is Crewlet’s id, the key a seat’s manages entry namesthe unit by. The displayName is for reading only: nothing refers to a unit by it, so two Units may share one. | MaxLength: 256 MinLength: 1 Optional: {} | |
type UnitType | type is an informational label. Crewlet’s type. | Enum: [Division Department Group Team Squad Pod Guild Chapter Unit] Optional: {} | |
parentRef LocalObjectReference | parentRef names the Unit this one belongs to. Unset makes it a top-level unit. A parent that does not exist, or a chain of parents that leads back to this unit, is reported on this Unit. | Optional: {} | |
leadRef LocalObjectReference | leadRef names the Seat that leads the unit. Unset inherits the parent’s lead. Crewlet’s lead. | Optional: {} | |
purpose string | purpose is what the unit is for. Crewlet’s purpose. | MaxLength: 2048 MinLength: 1 Optional: {} | |
goals string array | goals are what the unit is working toward. Crewlet’s goals. | MaxItems: 32 items:MaxLength: 1024 items:MinLength: 1 Optional: {} | |
channel string | channel is the unit’s channel on the company’s chat surface, such as #platform; child units without one inherit it. Crewlet’s channel. | MaxLength: 256 MinLength: 1 Optional: {} | |
knowledge string array | knowledge are free-text references to knowledge the unit relies on. They are not a read scope. Crewlet’s knowledge. | MaxItems: 32 items:MaxLength: 1024 items:MinLength: 1 Optional: {} | |
project string | project is the tracker project the unit files work in, by its key. Crewlet requires a container key to be an upper-case letter followed by 1 to 9 upper-case letters or digits, such as PLAT. Crewlet’s project. | MaxLength: 10 MinLength: 2 Pattern: ^[A-Z][A-Z0-9]\{1,9\}$ Optional: {} | |
space string | space is the knowledge container the unit writes pages in, by its key, which follows the same rule as project. Crewlet’s space. | MaxLength: 10 MinLength: 2 Pattern: ^[A-Z][A-Z0-9]\{1,9\}$ Optional: {} | |
mcp MCPCredentials array | mcp are tool-server credentials and settings every agent seat directly in this unit inherits; a seat’s own values win per variable. One entry per server, keyed by its name. Crewlet’s mcp_env, acredential position. Every credential comes from a Secret: the engine provisions a credential for one seat, and a unit’s are every member’s. A value one seat must not share, such as slack-mcp-server’s channel cache, belongs on the Seat. | MaxItems: 16 Optional: {} |
UnitStatus
Section titled “UnitStatus”UnitStatus is what the operator observed about a Unit.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
conditions Condition array | conditions are Accepted (the Company exists), ResolvedRefs (the parent, the lead, the tool servers and every Secret key exist, and the parents form no cycle) and Applied (the unit is in the revision the engine runs). | MaxItems: 8 Optional: {} | |
observedGeneration integer | observedGeneration is the metadata.generation this status describes. | Minimum: 1 Optional: {} | |
depth integer | depth is the unit’s distance from the top of the chart: 0 for a top-level unit. | Minimum: 0 Optional: {} | |
seats integer | seats is the number of Seats directly in the unit. | Minimum: 0 Optional: {} |
UnitType
Section titled “UnitType”Underlying type: string
UnitType is an informational label for a unit; nothing in the engine
behaves differently for one. It maps onto Crewlet’s well-known unit types
(Division is division, Team is team, and so on).
Validation:
- Enum: [Division Department Group Team Squad Pod Guild Chapter Unit]
Appears in:
| Field | Description |
|---|---|
Division | |
Department | |
Group | |
Team | |
Squad | |
Pod | |
Guild | |
Chapter | |
Unit |
WebhookExposure
Section titled “WebhookExposure”WebhookExposure is how vendors’ webhooks, and the calls a remote sandbox makes back to the engine, reach a company’s engine. Whatever the mode, they reach the engine’s public listener (Crewlet’s api.public), a port of its own that serves only the routes outside parties call without an operator credential (/webhooks/, /otlp/{token}, /mcp/{token}) and answers every other path as one nothing serves; the admin API, the dashboard and the probes are on the API port, which this never reaches.
Validation:
- MinProperties: 1
Appears in:
| Field | Description | Default | Validation |
|---|---|---|---|
mode WebhookExposureMode | mode is how webhooks reach the engine. | None | Enum: [Gateway Ingress External None] Optional: {} |
gateway GatewayExposure | gateway is the Gateways to attach to, for mode Gateway. | Optional: {} | |
ingress IngressExposure | ingress is the Ingress settings, for mode Ingress. | Optional: {} | |
external ExternalExposure | external is where the forwarder runs, for mode External. | MinProperties: 1 Optional: {} | |
hostname string | hostname is the public host name of each company, as a template: {{namespace}}, {{name}} and {{uid}} are replaced by the Company’s namespace, name and UID. The result is the company’s public base URL, https:// {{uid}}: the host name is public, and a UID says nothing about the tenant where a name can; and a UID is never reused, so a vendor still configured for a deleted company can never reach a company created later under the same name. The template must contain {{uid}}, or {{name}} and {{namespace}} joined by a ’.’, which neither can hold, so that no two companies share a host name: with a ’-’ between them, team-a/b-web and team-a-b/web would. | MaxLength: 253 MinLength: 1 Optional: {} |
WebhookExposureMode
Section titled “WebhookExposureMode”Underlying type: string
WebhookExposureMode is how vendors’ webhooks reach a company’s engine.
Validation:
- Enum: [Gateway Ingress External None]
Appears in:
| Field | Description |
|---|---|
Gateway | WebhookExposureGateway routes the public hostname to the engine’s public listener with an HTTPRoute. |
Ingress | WebhookExposureIngress does the same with an Ingress. |
External | WebhookExposureExternal creates nothing public: something outside the operator (a relay, an API gateway) forwards to the public port of the engine’s Service, and each Company states the address it is reached on in spec.exposure.publicBaseURL. |
None | WebhookExposureNone exposes nothing; integrations that need inbound delivery report that they are not exposed. |
WorkingStatus
Section titled “WorkingStatus”Underlying type: string
WorkingStatus is when a seat shows that it is working on a chat message. It
maps onto Crewlet’s typing_status (Always is always, Addressed is
addressed).
Validation:
- Enum: [Always Addressed]
Appears in:
| Field | Description |
|---|---|
Always | WorkingStatusAlways shows it on every turn a chat message started. |
Addressed | WorkingStatusAddressed shows it only when a person is plausibly waiting: a direct message, a mention, or a thread the seat follows. |
Part of Crewlet. Generated from crewlet/crewlet-operator main at d1515a2.