Skip to content
Operator has no release yet: these pages describe unreleased main.

API Reference

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.

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:

FieldDescriptionDefaultValidation
mode APIExposureModemode is how the API is reached.ClusterInternalEnum: [ClusterInternal Gateway Ingress]
Optional: {}
gateway GatewayExposuregateway is the Gateways to attach to, for mode Gateway.Optional: {}
ingress IngressExposureingress is the Ingress settings, for mode Ingress.Optional: {}
hostname stringhostname 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: {}

Underlying type: string

APIExposureMode is how a company’s engine API is reached from outside its namespace.

Validation:

  • Enum: [ClusterInternal Gateway Ingress]

Appears in:

FieldDescription
ClusterInternalAPIExposureClusterInternal reaches the API only through the company’s
Service, from inside the cluster.
GatewayAPIExposureGateway 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.
IngressAPIExposureIngress does the same with an Ingress.

AppliedObjectCounts is how many objects of each kind the applied revision was rendered from.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
units integerunits is the number of Units.Minimum: 0
Optional: {}
seats integerseats is the number of Seats.Minimum: 0
Optional: {}
llmProviders integerllmProviders is the number of model providers, platform providers
included.
Minimum: 0
Optional: {}
mcpServers integermcpServers is the number of MCPServers.Minimum: 0
Optional: {}
integrations integerintegrations is the number of Integrations.Minimum: 0
Optional: {}
schedules integerschedules is the number of Schedules.Minimum: 0
Optional: {}

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:

FieldDescriptionDefaultValidation
mode ArtifactExposureModemode is how the artifact origin is reached.NoneEnum: [None Gateway Ingress]
Optional: {}
gateway GatewayExposuregateway is the Gateways to attach to, for mode Gateway; a listener the
route attaches to must be HTTPS.
Optional: {}
ingress IngressExposureingress is the Ingress settings, for mode Ingress; tls is required.Optional: {}
hostname stringhostname 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 ArtifactOriginsorigins is PerArtifact (unset), where the route takes *., or
Shared, where it takes .
Enum: [PerArtifact Shared]
Optional: {}

Underlying type: string

ArtifactExposureMode is how browsers reach a company’s artifact origin.

Validation:

  • Enum: [None Gateway Ingress]

Appears in:

FieldDescription
NoneArtifactExposureNone routes nothing; the Company may state an address
(spec.exposure.artifactsBaseURL).
GatewayArtifactExposureGateway routes the artifact hosts with an HTTPRoute.
IngressArtifactExposureIngress does the same with an Ingress.

Underlying type: string

ArtifactOrigins is how artifacts are kept apart in a browser.

Validation:

  • Enum: [PerArtifact Shared]

Appears in:

FieldDescription
PerArtifactArtifactOriginsPerArtifact gives each artifact a host under the route’s
host name: its own origin, which needs a wildcard DNS name and certificate.
SharedArtifactOriginsShared serves every artifact from one host, each with an
opaque origin and no browser storage.

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:

FieldDescriptionDefaultValidation
orgID stringorgID is the organization’s id, from admin.atlassian.com. Crewlet’s
org_id.
MaxLength: 64
MinLength: 1
Pattern: ^[A-Za-z0-9-]+$
Required: {}
apiKeySecretRef SecretKeyReferenceapiKeySecretRef 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 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:

FieldDescriptionDefaultValidation
mode CLIAgentAuthModemode is how the CLI signs in. Unset is Subscription. Crewlet’s
mode.
Enum: [Subscription APIKey]
Optional: {}
tokenSecretRef SecretKeyReferencetokenSecretRef is the Secret key holding a long-lived subscription
token the CLI mints for headless use. Crewlet’s token, a credential
position.
Optional: {}
credentialBundleSecretRef SecretKeyReferencecredentialBundleSecretRef is the Secret key holding a credential
bundle crewlet llm export wrote. A bundle holding a login OpenCode
1.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: {}

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:

FieldDescription
SubscriptionCLIAgentAuthSubscription 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.
APIKeyCLIAgentAuthAPIKey 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.

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:

FieldDescription
TextCLIAgentModeText drives the CLI as a text model behind the engine’s
own tool loop, as a process in the engine’s pod.
AgentCLIAgentModeAgent 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.

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:

FieldDescription
ClaudeCode
Codex
GeminiCLI
QwenCode
OpenCode
CursorAgent
Copilot
Grok
MuseCode
KimiCode
Hermes
Pi

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:

FieldDescription
E2BCLIAgentRunInE2B is the Company’s E2B sandbox.

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:

FieldDescriptionDefaultValidation
agent CLIAgentNameagent 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 CLIAgentModemode is how the engine uses the CLI. Unset is Text. Crewlet’s mode.Enum: [Text Agent]
Optional: {}
runIn CLIAgentRunInrunIn is where an Agent-mode run happens. Unset is the Company’s
sandbox, which is E2B. Crewlet’s run_in.
Enum: [E2B]
Optional: {}
auth CLIAgentAuthauth is how the CLI signs in.MinProperties: 1
Required: {}
env SecretEnvVar arrayenv 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 integertimeoutSeconds caps one invocation of the CLI, launch included. Unset
takes Crewlet’s default of 300. Crewlet’s timeout_seconds.
Minimum: 1
Optional: {}
maxConcurrent integermaxConcurrent 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 stringloginName 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 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:

FieldDescriptionDefaultValidation
name stringname is the variable’s name.MaxLength: 128
MinLength: 1
Pattern: ^[A-Za-z_][A-Za-z0-9_]*$
Required: {}
value stringvalue 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 NamespacedSecretValueSourcevalueFrom reads the value from a Secret key in a namespace the
platform controls.
Optional: {}

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:

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:

FieldDescription
ClaudeCodeCodingAgentClaudeCode is Claude Code.
OpenCodeCodingAgentOpenCode is OpenCode.

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.

FieldDescriptionDefaultValidation
apiVersion stringcrewlet.ai/v1alpha1
kind stringCompany
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.Optional: {}
spec CompanySpecspec is the company’s desired state.Required: {}
status CompanyStatusstatus is the company’s observed state.MinProperties: 1
Optional: {}

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:

FieldDescriptionDefaultValidation
api stringapi 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 stringexposedAPI 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:// otherwise,
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 stringpublicBaseURL 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://-engine.
.svc:8081, which no vendor can reach.
MaxLength: 2048
MinLength: 1
Optional: {}
dashboardBaseURL stringdashboardBaseURL 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 stringartifactsBaseURL 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 overrides how a company is reached.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
publicBaseURL stringpublicBaseURL 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 stringdashboardBaseURL 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 stringartifactsBaseURL 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 is company-wide behaviour of the integration reconcile loop. The vendors themselves are Integration objects.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
checkIntervalSeconds integercheckIntervalSeconds 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 is how a company chooses among its model providers.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
order LLMProviderReference arrayorder 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 booleanusePlatformProviders 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 is a company’s own access to its class’s object store.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
credentialsSecretRef SecretReferencecredentialsSecretRef 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 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:

FieldDescriptionDefaultValidation
name stringname is the metadata.name of a Company in this object’s namespace.MaxLength: 253
MinLength: 1
Required: {}

CompanyRuntime is a company’s bounded overrides of its class.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
version stringversion 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 arrayenv 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 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:

FieldDescriptionDefaultValidation
engineClassName stringengineClassName 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 stringcompanyName 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 stringmission is one line on what the company is for; every seat’s prompt
carries it. Crewlet’s mission.
MaxLength: 2048
MinLength: 1
Optional: {}
vision stringvision is a longer statement of where the company is going. Crewlet’s
vision.
MaxLength: 8192
MinLength: 1
Optional: {}
policies string arraypolicies are company-wide rules every seat’s prompt carries. Crewlet’s
policies.
MaxItems: 64
items:MaxLength: 2048
items:MinLength: 1
Optional: {}
timeZone stringtimeZone 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 TrackerSettingstracker is which work tracker the company runs.MinProperties: 1
Optional: {}
knowledge KnowledgeSettingsknowledge is which knowledge base the company runs.MinProperties: 1
Optional: {}
tokenBudget TokenBudgettokenBudget caps the tokens all seats together may spend per window.
Crewlet’s token_budget.
MinProperties: 1
Optional: {}
llm CompanyLLMSettingsllm is how the company chooses among its model providers.MinProperties: 1
Optional: {}
embeddings EmbeddingSettingsembeddings is the provider vectors are computed with. Unset leaves
search keyword-only. Crewlet’s providers.embeddings.
Optional: {}
sandbox SandboxSettingssandbox is where seats run code. Unset gives no seat a sandbox.
Crewlet’s providers.sandbox.
Optional: {}
integrations CompanyIntegrationSettingsintegrations is company-wide integration behaviour.MinProperties: 1
Optional: {}
engineConfig EngineConfigEntry arrayengineConfig 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 ConfigSettingsconfig is how the operator manages the company’s document.{ managementPolicy:Enforce }MinProperties: 1
Optional: {}
topology CompanyTopologytopology is how the engine is laid out in pods.{ data:map[replicas:1] }MinProperties: 1
Optional: {}
exposure CompanyExposureexposure overrides how the company is reached.MinProperties: 1
Optional: {}
runtime CompanyRuntimeruntime is the company’s bounded overrides of its class.MinProperties: 1
Optional: {}
objects CompanyObjectsobjects is the company’s own access to its class’s object store.MinProperties: 1
Optional: {}
suspend booleansuspend 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 DeletionPolicydeletionPolicy 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.
RetainEnum: [Retain Delete]
Optional: {}

CompanyStatus is what the operator observed about a Company.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
conditions Condition arrayconditions 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 integerobservedGeneration is the metadata.generation this status describes.Minimum: 1
Optional: {}
engine EngineStatusengine is what runs the company.MinProperties: 1
Optional: {}
topology TopologyStatustopology is the state of the company’s pods.MinProperties: 1
Optional: {}
config ConfigStatusconfig is the revision the engine runs.MinProperties: 1
Optional: {}
endpoints CompanyEndpointsendpoints is where the company is reached.MinProperties: 1
Optional: {}
apiAccessSecretRef SecretReferenceapiAccessSecretRef 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 -api-tokens, -keyring and
-bootstrap.
Optional: {}

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:

FieldDescriptionDefaultValidation
data DataTopologydata is the pods that hold the estate.{ replicas:1 }MinProperties: 1
Optional: {}
defaultSeatPool stringdefaultSeatPool is the pool of every agent seat whose Seat names no
spec.placement.pool: data, or the name of a Shared pool of seatPools.
dataMaxLength: 20
MinLength: 1
Pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
Optional: {}
seatPools SeatPool arrayseatPools 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 is how the operator manages a company’s document.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
managementPolicy ManagementPolicymanagementPolicy 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.
EnforceEnum: [Enforce Observe Seed]
Optional: {}

ConfigStatus is the revision of the company document the engine runs.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
revisionID stringrevisionID 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 integerepoch 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 stringappliedHash 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 TimeappliedAt is when the operator last applied a revision.Optional: {}
objects AppliedObjectCountsobjects counts the objects the revision was rendered from.MinProperties: 1
Optional: {}
placement RevisionPlacementplacement 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 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:

FieldDescriptionDefaultValidation
url stringurl 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 stringcloudID 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 stringsiteURL 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 stringemail 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 SecretKeyReferencetokenSecretRef 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 SecretKeyReferencewebhookSecretRef 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 SecretKeyReferencewebhookTokenSecretRef 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 credential
position.
Optional: {}

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:

FieldDescription
AutoContainerWebhookAuto uses one organization hook where the token may
create one, and per-repository hooks otherwise.
RequireContainerWebhookRequire demands an organization hook.
NeverContainerWebhookNever always registers per-repository hooks.

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:

FieldDescriptionDefaultValidation
allowedReplicas integer arrayallowedReplicas 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 ResourceRequirementsresources are the compute resources of the engine container.Optional: {}
storage DataStoragestorage is the data volume each data pod gets.Required: {}
startupSeconds integerstartupSeconds 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 integerterminationGracePeriodSeconds 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.
300Maximum: 3600
Minimum: 30
Optional: {}

DataStorage is the volume each data pod keeps the company’s estate on.

Appears in:

FieldDescriptionDefaultValidation
storageClassName stringstorageClassName is the StorageClass of the data volumes. Unset uses
the cluster’s default class.
MaxLength: 253
MinLength: 1
Optional: {}
size Quantitysize 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 is the pods that hold a company’s estate.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
replicas integerreplicas 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.
1Enum: [1]
Minimum: 1
Optional: {}

DataTopologyStatus is the state of a company’s data pods.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
replicas integerreplicas is the number of data pods.Minimum: 0
Optional: {}
readyReplicas integerreadyReplicas is the number of data pods that are ready.Minimum: 0
Optional: {}
updatedReplicas integerupdatedReplicas is the number of data pods that run the current pod
template.
Minimum: 0
Optional: {}

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:

FieldDescriptionDefaultValidation
webhookTokenSecretRef SecretKeyReferencewebhookTokenSecretRef 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 DatadogRouteTorouteTo is where an alert goes whose monitor names no seat.
Crewlet’s route_to.
MinProperties: 1
Required: {}
site DatadogSitesite 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 SecretKeyReferenceapiKeySecretRef 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 SecretKeyReferenceappKeySecretRef 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 stringrole 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 stringemailDomain 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 stringwebhookName is the name of the webhook the engine keeps at Datadog,
and so the handle monitors write: @webhook-. Unset is crewlet.
Crewlet’s webhook_name.
MaxLength: 128
MinLength: 1
Pattern: ^[^ @,]+$
Optional: {}
handleTag stringhandleTag 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 is where an alert goes whose monitor names no seat.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
seatRef LocalObjectReferenceseatRef names the agent Seat, in this namespace, the alert wakes.
Crewlet’s route_to, as the seat’s handle.
Optional: {}
dismiss booleandismiss 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: {}

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:

FieldDescription
US1
US3
US5
EU1
AP1
AP2
US1FED

Underlying type: string

DeletionPolicy is what happens to a company’s data volumes when the Company is deleted.

Validation:

  • Enum: [Retain Delete]

Appears in:

FieldDescription
RetainDeletionPolicyRetain keeps the data volumes and the keyring Secret
-keyring that opens the secrets sealed on them. A Company created
again with the same name and namespace finds both and its estate again.
DeleteDeletionPolicyDelete deletes them with the Company.

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:

FieldDescriptionDefaultValidation
apiKeySecretRef SecretKeyReferenceapiKeySecretRef is the Secret key holding the service’s API key.
Crewlet’s api_key, a credential position.
Required: {}
domain stringdomain points at a self-hosted cluster of the service. Unset is the
vendor’s cloud.
MaxLength: 253
MinLength: 1
Optional: {}
template stringtemplate 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: {}

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:

FieldDescription
OpenAIEmbeddingProviderOpenAI is OpenAI’s embeddings API.
OpenAICompatibleEmbeddingProviderOpenAICompatible is any endpoint that speaks it.

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:

FieldDescriptionDefaultValidation
type EmbeddingProviderTypetype is which embeddings API the provider speaks.OpenAIEnum: [OpenAI OpenAICompatible]
Optional: {}
model stringmodel is the embedding model id. Crewlet’s model. Crewlet trims it of
white space and refuses an embeddings provider with nothing left, as
naming no model.
MaxLength: 256
MinLength: 1
Required: {}
apiKeySecretRef SecretKeyReferenceapiKeySecretRef is the Secret key holding the API key. Crewlet’s
api_key, a credential position. Required for type OpenAI: Crewlet
reads 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 stringbaseURL is the endpoint of an OpenAI-compatible service. Crewlet’s
base_url.
MaxLength: 2048
MinLength: 1
Optional: {}
dimensions integerdimensions 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 integermaxInputTokens is the most tokens one input may hold. Unset takes the
model’s documented window; it may only lower it.
Minimum: 1
Optional: {}
maxBatchInputs integermaxBatchInputs is the most inputs one request may carry. Unset takes
the model’s documented limit; it may only lower it.
Minimum: 1
Optional: {}
maxBatchTokens integermaxBatchTokens 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 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.

FieldDescriptionDefaultValidation
apiVersion stringcrewlet.ai/v1alpha1
kind stringEngineClass
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.Optional: {}
spec EngineClassSpecspec is the class’s desired state.Required: {}
status EngineClassStatusstatus is the class’s observed state.MinProperties: 1
Optional: {}

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:

FieldDescriptionDefaultValidation
allowedNamespaces LabelSelectorallowedNamespaces 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 EngineSettingsengine is the engine image.Required: {}
data DataPodSettingsdata sizes the pods that hold each company’s estate.Required: {}
seatPools SeatPoolSettingsseatPools is whether each company may run seats on stateless pods of
its own, and how many.
{ policy:Forbidden }MinProperties: 1
Optional: {}
stream StreamSettingsstream is how each company’s event stream runs.{ mode:Embedded }MinProperties: 1
Optional: {}
objects ObjectSettingsobjects is where each company’s files are kept.{ backend:NATS }MinProperties: 1
Optional: {}
exposure ExposureSettingsexposure 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 NetworkPolicySettingsnetworkPolicy is the NetworkPolicy the operator puts around each
company’s engine pods.
{ mode:Isolated }MinProperties: 1
Optional: {}
podTemplate EnginePodTemplatepodTemplate is what is added to every engine pod.MinProperties: 1
Optional: {}
serviceAccount EngineServiceAccountserviceAccount is what is added to each company’s engine
ServiceAccount.
MinProperties: 1
Optional: {}
service EngineServiceservice is what is added to each company’s engine Service, which the
class’s routes send to.
MinProperties: 1
Optional: {}
platformLLMProviders PlatformLLMProvider arrayplatformLLMProviders are model providers the platform offers to
companies that opt in.
MaxItems: 16
Optional: {}
limits EngineLimitslimits caps what a company may declare.MinProperties: 1
Optional: {}
telemetry TelemetrySettingstelemetry sends the engine’s traces to a collector. Unset exports
nothing.
Optional: {}
retention RetentionSettingsretention is who answers for backups.Optional: {}
signIn SignInSettingssignIn 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 is what the operator observed about an EngineClass.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
conditions Condition arrayconditions 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 integerobservedGeneration is the metadata.generation this status describes.Minimum: 1
Optional: {}

EngineConfigEntry is one top-level key of the company document that spec.engineConfig passes through, and its value.

Appears in:

FieldDescriptionDefaultValidation
name stringname is the key, as Crewlet spells it, such as turn_engine.MaxLength: 63
MinLength: 1
Pattern: ^[a-z][a-z0-9_]*$
Required: {}
value EngineConfigValuevalue is the key’s value: an object, a list, a string, a number or a
boolean, kept as written.
Type:
Required: {}

EngineConfigValue is any JSON value, kept byte for byte as it was written.

Validation:

  • Type:

Appears in:

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:

FieldDescriptionDefaultValidation
maxSeats integermaxSeats is the most Seats a Company may have. Unset is unlimited.Minimum: 0
Optional: {}
maxMCPServers integermaxMCPServers is the most MCPServers a Company may have. Unset is
unlimited.
Minimum: 0
Optional: {}

EnginePodMetadata is metadata added to every engine pod.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
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 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:

FieldDescriptionDefaultValidation
nodeSelector object (keys:string, values:string)nodeSelector constrains engine pods to nodes with these labels.MaxProperties: 32
Optional: {}
tolerations Toleration arraytolerations let engine pods run on tainted nodes.MaxItems: 32
Optional: {}
affinity Affinityaffinity is the engine pods’ scheduling affinity.Optional: {}
topologySpreadConstraints TopologySpreadConstraint arraytopologySpreadConstraints spread engine pods across topology domains.MaxItems: 8
Optional: {}
runtimeClassName stringruntimeClassName is the RuntimeClass engine pods run with, for example
a sandboxed runtime such as gVisor.
MaxLength: 253
MinLength: 1
Optional: {}
priorityClassName stringpriorityClassName is the PriorityClass of engine pods.MaxLength: 253
MinLength: 1
Optional: {}
env ClassEnvVar arrayenv 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 is what a class adds to every engine pod.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
metadata EnginePodMetadataRefer to Kubernetes API documentation for fields of metadata.MinProperties: 1
Optional: {}
spec EnginePodSpecspec is merged into every engine pod’s spec.MinProperties: 1
Optional: {}

EngineService is what a class adds to the Service -engine the operator creates in front of each Company’s data pods, which the class’s routes send to. It has no Crewlet field: the engine never sees its Service.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
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 is what a class adds to the ServiceAccount the operator creates for each Company’s engine pods.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
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 is the engine image a class runs.

Appears in:

FieldDescriptionDefaultValidation
image stringimage 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 PullPolicyimagePullPolicy is the pull policy of the engine container. Unset
takes the Kubernetes default for the image reference.
Enum: [Always IfNotPresent Never]
Optional: {}
imagePullSecrets LocalObjectReference arrayimagePullSecrets 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 booleanallowVersionOverride 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 is what runs a company.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
image stringimage 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 stringversion 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 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:

FieldDescriptionDefaultValidation
name stringname is the variable’s name.MaxLength: 128
MinLength: 1
Pattern: ^[A-Za-z_][A-Za-z0-9_]*$
Required: {}
value stringvalue 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 SecretValueSourcevalueFrom reads the value from a Secret key in the Company’s namespace.Optional: {}

ExposureSettings is how a class’s companies are reached.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
webhooks WebhookExposurewebhooks is how vendors’ webhooks reach the engine.{ mode:None }MinProperties: 1
Optional: {}
api APIExposureapi is how the engine’s API is reached.{ mode:ClusterInternal }MinProperties: 1
Optional: {}
artifacts ArtifactExposureartifacts is how browsers reach the artifact origin.{ mode:None }MinProperties: 1
Optional: {}
trustedProxies string arraytrustedProxies 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 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:

FieldDescriptionDefaultValidation
forwarders NetworkPolicyPeer arrayforwarders 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 attaches a company’s routes to Gateways.

Appears in:

FieldDescriptionDefaultValidation
parentRefs GatewayParentReference arrayparentRefs are the Gateways the HTTPRoute attaches to.MaxItems: 8
MinItems: 1
Required: {}
proxyNamespaces string arrayproxyNamespaces 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 names a Gateway API Gateway (or one listener of it) that the operator attaches a company’s HTTPRoute to.

Appears in:

FieldDescriptionDefaultValidation
namespace stringnamespace is the Gateway’s namespace. Unset is the Company’s own
namespace.
MaxLength: 63
MinLength: 1
Optional: {}
name stringname is the Gateway’s name.MaxLength: 253
MinLength: 1
Required: {}
sectionName stringsectionName is the name of one listener of the Gateway. Unset attaches
to every listener that accepts the route.
MaxLength: 253
MinLength: 1
Optional: {}

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:

FieldDescription
ReadOnly
Review
FullAccess

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:

FieldDescriptionDefaultValidation
id integerid is the app’s numeric id. Crewlet’s app_id.Minimum: 1
Required: {}
slug stringslug 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 integerinstallationID 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 SecretReferencecredentialsSecretRef 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_key
and webhook_secret, both credential positions.
Required: {}

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:

FieldDescriptionDefaultValidation
url stringurl 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 SecretKeyReferencewebhookSecretRef 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 SecretKeyReferencetokenSecretRef 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 credential
position.
Optional: {}
provisioning GitHubProvisioningprovisioning is where the webhooks are registered. It requires
tokenSecretRef, without which the engine registers nothing.
MinProperties: 1
Optional: {}

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:

FieldDescriptionDefaultValidation
org stringorg is the GitHub organization holding the repositories. Crewlet’s
org.
MaxLength: 39
MinLength: 1
Pattern: ^[A-Za-z0-9-]+$
Optional: {}
repos string arrayrepos 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 ContainerWebhookModeorgWebhook is whether one organization hook replaces the
per-repository ones. Unset is Auto. Crewlet’s org_webhook.
Enum: [Auto Require Never]
Optional: {}

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:

FieldDescriptionDefaultValidation
tier GitHubAccessTiertier is how much the seat may do in a repository. Unset is ReadOnly.
Crewlet’s tier.
Enum: [ReadOnly Review FullAccess]
Optional: {}
repos string arrayrepos 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 GitHubAppapp is the GitHub App the seat acts as.Optional: {}

GitHubSeatStatus is the GitHub side of a seat, as the operator computed it.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
webhookURL stringwebhookURL is the URL the seat’s GitHub App must deliver webhooks to,
/webhooks/github/. Like the Slack requestURL it
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: {}

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:

FieldDescription
DeveloperGitLabDeveloper can push branches and open merge requests.
MaintainerGitLabMaintainer can also merge to protected branches.

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:

FieldDescription
GroupGitLabAccountOwnerGroup creates them under the group, which is all
GitLab.com offers.
InstanceGitLabAccountOwnerInstance creates them on a self-managed instance
itself, with an instance administrator’s token.

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:

FieldDescriptionDefaultValidation
group stringgroup 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 SecretKeyReferenceadminTokenSecretRef 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 GitLabAccountOwneraccountOwner is where the service accounts are created. Unset is
Group. Crewlet’s mode.
Enum: [Group Instance]
Optional: {}
accessLevel GitLabAccessLevelaccessLevel 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 arrayaccessLevels override accessLevel for single seats. Crewlet’s
access_levels.
MaxItems: 64
Optional: {}
usernamePrefix stringusernamePrefix 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 arrayprojects 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 ContainerWebhookModegroupWebhook is whether one group hook replaces the per-project ones.
Unset is Auto. Crewlet’s group_webhook.
Enum: [Auto Require Never]
Optional: {}
tokenScopes string arraytokenScopes 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 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:

FieldDescriptionDefaultValidation
url stringurl is the instance’s base URL, such as https://gitlab.com. Crewlet’s
url.
MaxLength: 2048
MinLength: 1
Required: {}
signingSecretRef SecretKeyReferencesigningSecretRef 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, a
credential position.
Required: {}
tokenSecretRef SecretKeyReferencetokenSecretRef 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 stringwebhookName 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 GitLabEngineProvisioningengineProvisioning is how the engine creates the seats’ accounts.
Required with provisioning Engine, and not allowed with External.
Optional: {}

GitLabSeatAccess overrides the access level of one seat’s service account.

Appears in:

FieldDescriptionDefaultValidation
name stringname 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 GitLabAccessLevelaccessLevel is the seat’s membership level.Enum: [Developer Maintainer]
Required: {}

IngressExposure puts a company’s routes on an Ingress.

Appears in:

FieldDescriptionDefaultValidation
className stringclassName 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 IngressTLStls 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 arraycontrollerNamespaces 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 terminates TLS on a company’s Ingress.

Appears in:

FieldDescriptionDefaultValidation
secretName stringsecretName 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 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.

FieldDescriptionDefaultValidation
apiVersion stringcrewlet.ai/v1alpha1
kind stringIntegration
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.Optional: {}
spec IntegrationSpecspec is the integration’s desired state.Required: {}
status IntegrationStatusstatus is the integration’s observed state.MinProperties: 1
Optional: {}

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:

FieldDescription
ExternalIntegrationProvisioningExternal 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.
EngineIntegrationProvisioningEngine 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 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:

FieldDescriptionDefaultValidation
companyRef CompanyReferencecompanyRef names the Company this integration belongs to. Immutable.Required: {}
provisioning IntegrationProvisioningprovisioning is who creates the seats’ accounts at the vendor. Unset
is External.
Enum: [External Engine]
Optional: {}
slack SlackIntegrationslack connects Slack.Optional: {}
github GitHubIntegrationgithub connects GitHub.Optional: {}
gitlab GitLabIntegrationgitlab connects GitLab.Optional: {}
mattermost MattermostIntegrationmattermost connects Mattermost.Optional: {}
jira JiraIntegrationjira connects Jira.Optional: {}
confluence ConfluenceIntegrationconfluence connects Confluence.Optional: {}
datadog DatadogIntegrationdatadog connects Datadog.Optional: {}
atlassian AtlassianIntegrationatlassian connects an Atlassian Cloud organization.Optional: {}

IntegrationStatus is what the operator observed about an Integration.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
conditions Condition arrayconditions 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 integerobservedGeneration is the metadata.generation this status describes.Minimum: 1
Optional: {}
webhookURL stringwebhookURL is the company-wide URL the vendor delivers webhooks to,
when the company is exposed and the vendor has one:
/webhooks/ for GitHub, GitLab, Jira,
Confluence (a Data Center instance’s; Confluence Cloud delivers to
/, a hook the engine registers per event) and
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 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:

FieldDescriptionDefaultValidation
url stringurl 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 stringcloudID 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 stringsiteURL 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 stringemail 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 SecretKeyReferencetokenSecretRef 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 credential
position.
Required: {}
webhookSecretRef SecretKeyReferencewebhookSecretRef 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 stringwebhookName 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: {}

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:

FieldDescription
NativeKnowledgeNative is the engine’s own knowledge base.
ConfluenceKnowledgeConfluence is Confluence, connected by the company’s
Confluence Integration.
NoneKnowledgeNone is a company with no knowledge base.

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:

FieldDescriptionDefaultValidation
backend KnowledgeBackendbackend is which knowledge base the company runs.NativeEnum: [Native Confluence None]
Optional: {}
scope string arrayscope 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 stringskillsContainer 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 stringrootSpace 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 booleanvectors 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 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:

FieldDescriptionDefaultValidation
rateLimitSeconds integerrateLimitSeconds 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 integerauthSeconds is how long a key the provider refused is set aside. Unset
takes Crewlet’s default of 300.
Maximum: 86400
Minimum: 60
Optional: {}

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.

FieldDescriptionDefaultValidation
apiVersion stringcrewlet.ai/v1alpha1
kind stringLLMProvider
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.Optional: {}
spec LLMProviderSpecspec is the provider’s desired state.Required: {}
status LLMProviderStatusstatus is the provider’s observed state.MinProperties: 1
Optional: {}

Underlying type: string

LLMProviderKind is the kind of model provider a reference names.

Validation:

  • Enum: [LLMProvider PlatformLLMProvider]

Appears in:

FieldDescription
LLMProviderLLMProviderKindLLMProvider is an LLMProvider in the referring object’s
namespace.
PlatformLLMProviderLLMProviderKindPlatform is an entry of the Company’s EngineClass
spec.platformLLMProviders; the Company must set
spec.llm.usePlatformProviders.

LLMProviderReference names a model provider: an LLMProvider in the referring object’s namespace, or a provider the EngineClass offers.

Appears in:

FieldDescriptionDefaultValidation
kind LLMProviderKindkind is the kind of provider named.LLMProviderEnum: [LLMProvider PlatformLLMProvider]
Optional: {}
name stringname is the LLMProvider’s metadata.name, or the platform provider’s
name.
MaxLength: 253
MinLength: 1
Required: {}

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:

FieldDescriptionDefaultValidation
type LLMProviderTypetype is which model API the provider speaks. Crewlet’s type.Enum: [Anthropic OpenAI OpenAICompatible CLIAgent]
Required: {}
model stringmodel is the model id requests are sent for, as the provider names it.
Crewlet’s model. Crewlet trims it of white space and refuses a
provider with nothing left, as naming no model.
MaxLength: 256
MinLength: 1
Required: {}
claudeModel ClaudeModelIDclaudeModel 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 stringbaseURL 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 booleanreasoning turns on an OpenAI reasoning model’s effort, so that
reasoningEffort is sent. Crewlet’s reasoning; type OpenAI only.
Optional: {}
reasoningEffort ReasoningEffortreasoningEffort 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 integerreasoningBudgetTokens 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 integertimeoutSeconds 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 LLMCredentialCooldownscooldowns is how long a failing key is set aside. Crewlet’s
cooldowns.
MinProperties: 1
Optional: {}

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:

FieldDescriptionDefaultValidation
companyRef CompanyReferencecompanyRef names the Company this provider belongs to. Immutable.Required: {}
type LLMProviderTypetype is which model API the provider speaks. Crewlet’s type.Enum: [Anthropic OpenAI OpenAICompatible CLIAgent]
Required: {}
model stringmodel is the model id requests are sent for, as the provider names it.
Crewlet’s model. Crewlet trims it of white space and refuses a
provider with nothing left, as naming no model.
MaxLength: 256
MinLength: 1
Required: {}
claudeModel ClaudeModelIDclaudeModel 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 stringbaseURL 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 booleanreasoning turns on an OpenAI reasoning model’s effort, so that
reasoningEffort is sent. Crewlet’s reasoning; type OpenAI only.
Optional: {}
reasoningEffort ReasoningEffortreasoningEffort 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 integerreasoningBudgetTokens 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 integertimeoutSeconds 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 LLMCredentialCooldownscooldowns is how long a failing key is set aside. Crewlet’s
cooldowns.
MinProperties: 1
Optional: {}
apiKeySecretRefs SecretKeyReference arrayapiKeySecretRefs 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, a
credential 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 CLIAgentSettingscli is the coding CLI a provider of type CLIAgent drives. Required
for, and only for, type CLIAgent. Crewlet’s cli.
Optional: {}

LLMProviderStatus is what the operator observed about an LLMProvider.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
conditions Condition arrayconditions 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 integerobservedGeneration is the metadata.generation this status describes.Minimum: 1
Optional: {}

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:

FieldDescription
AnthropicLLMProviderAnthropic is Anthropic’s Messages API.
OpenAILLMProviderOpenAI is OpenAI’s API.
OpenAICompatibleLLMProviderOpenAICompatible is any endpoint that speaks the OpenAI wire
format: a gateway, an aggregator, a self-hosted inference server.
CLIAgentLLMProviderCLIAgent drives a coding CLI (Claude Code, Codex, …) on a
subscription login, installed in the engine’s image: see
LLMProviderSpec.cli.

LocalObjectReference names another object of the kind the referring field documents, in the referring object’s own namespace.

Appears in:

FieldDescriptionDefaultValidation
name stringname is the metadata.name of the referenced object.MaxLength: 253
MinLength: 1
Required: {}

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:

FieldDescriptionDefaultValidation
name stringname is the environment variable’s name (Stdio) or the header’s name
(HTTP).
MaxLength: 128
MinLength: 1
Pattern: ^[A-Za-z0-9!#$%&'*+.^_|~-]+$
Required: {}
value stringvalue 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 SeatCredentialSourcevalueFrom 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
”); a provisioned value is the credential alone, so provision
one for a variable rather than a header.
MinProperties: 1
Optional: {}

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:

FieldDescriptionDefaultValidation
name stringname is the metadata.name of the MCPServer, in this namespace, the
values are for.
MaxLength: 253
MinLength: 1
Required: {}
env MCPCredentialValue arrayenv 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 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:

FieldDescriptionDefaultValidation
name stringname is the variable’s name.MaxLength: 128
MinLength: 1
Pattern: ^[A-Za-z_][A-Za-z0-9_]*$
Required: {}
value stringvalue 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 SecretValueSourcevalueFrom reads a credential from a Secret key.Optional: {}

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:

FieldDescriptionDefaultValidation
name stringname is the header’s name.MaxLength: 128
MinLength: 1
Pattern: ^[A-Za-z0-9!#$%&'*+.^_|~-]+$
Required: {}
value stringvalue 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 SecretValueSourcevalueFrom reads a credential from a Secret key, which holds the whole
header value, scheme included (for example “Bearer ”).
Optional: {}

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.

FieldDescriptionDefaultValidation
apiVersion stringcrewlet.ai/v1alpha1
kind stringMCPServer
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.Optional: {}
spec MCPServerSpecspec is the server’s desired state.Required: {}
status MCPServerStatusstatus is the server’s observed state.MinProperties: 1
Optional: {}

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:

FieldDescriptionDefaultValidation
companyRef CompanyReferencecompanyRef names the Company this server belongs to. Immutable.Required: {}
transport MCPTransporttransport is how the engine reaches the server. Crewlet’s transport.StdioEnum: [Stdio HTTP]
Optional: {}
shared booleanshared 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.
trueOptional: {}
command stringcommand 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 it
passes on as written: it resolves no ${NAME} in it.
MaxLength: 1024
MinLength: 1
Optional: {}
args string arrayargs are the executable’s arguments. Crewlet’s args, which it passes
on as written: it resolves no ${NAME} in them.
MaxItems: 64
items:MaxLength: 4096
Optional: {}
env MCPEnvVar arrayenv 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 stringurl is the endpoint of an HTTP server. Crewlet’s url.MaxLength: 2048
MinLength: 1
Optional: {}
headers MCPHeader arrayheaders 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 arrayoptionalKeys 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 stringtoolPrefix 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 arraytoolAnnotations correct the hints individual tools advertise.
Crewlet’s tool_annotations.
MaxItems: 128
Optional: {}
startupTimeoutSeconds integerstartupTimeoutSeconds 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 integerrequestTimeoutSeconds bounds one tool call. Unset takes Crewlet’s
default of 300. Crewlet’s request_timeout_seconds.
Minimum: 1
Optional: {}

MCPServerStatus is what the operator observed about an MCPServer.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
conditions Condition arrayconditions 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 integerobservedGeneration is the metadata.generation this status describes.Minimum: 1
Optional: {}

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:

FieldDescriptionDefaultValidation
tool stringtool is the tool’s name as the server publishes it, without any
prefix.
MaxLength: 128
MinLength: 1
Required: {}
readOnly booleanreadOnly marks a tool that changes nothing. Crewlet’s read_only.Optional: {}
destructive booleandestructive marks a tool whose effect cannot be undone. Crewlet’s
destructive.
Optional: {}
idempotent booleanidempotent marks a tool that can be repeated safely. Crewlet’s
idempotent.
Optional: {}
openWorld booleanopenWorld marks a tool that reaches outside the company. Crewlet’s
open_world.
Optional: {}

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:

FieldDescription
StdioMCPTransportStdio 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.
HTTPMCPTransportHTTP connects to a remote server over Streamable HTTP.

Underlying type: string

ManagedKind is the kind of object a seat manages.

Validation:

  • Enum: [Seat Unit]

Appears in:

FieldDescription
SeatManagedKindSeat is a single Seat.
UnitManagedKindUnit is every seat of a Unit and of the units below it.

ManagedReference names a Seat or a Unit, in the referring Seat’s namespace, that a seat manages.

Appears in:

FieldDescriptionDefaultValidation
kind ManagedKindkind is the kind of object named.SeatEnum: [Seat Unit]
Optional: {}
name stringname is the object’s metadata.name.MaxLength: 253
MinLength: 1
Required: {}

Underlying type: string

ManagementPolicy says who owns a company’s live document.

Validation:

  • Enum: [Enforce Observe Seed]

Appears in:

FieldDescription
EnforceManagementPolicyEnforce 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.
ObserveManagementPolicyObserve renders and compares, and never writes; a
difference is reported only. The engine’s own users may change the
document.
SeedManagementPolicySeed 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 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:

FieldDescriptionDefaultValidation
adminTokenSecretRef SecretKeyReferenceadminTokenSecretRef 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 stringusernamePrefix 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 arraychannels 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 stringdisplayNameSuffix 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 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:

FieldDescriptionDefaultValidation
url stringurl 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 stringteam 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 WorkingStatustypingStatus 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 MattermostEngineProvisioningengineProvisioning is how the engine creates the seats’ bots.
Required with provisioning Engine, and not allowed with External.
Optional: {}

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:

FieldDescriptionDefaultValidation
botToken SeatCredentialSourcebotToken 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 stringusername 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 stringchannel 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 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:

FieldDescriptionDefaultValidation
namespace stringnamespace is the namespace the Secret is in.MaxLength: 63
MinLength: 1
Required: {}
name stringname is the metadata.name of the Secret.MaxLength: 253
MinLength: 1
Required: {}
key stringkey is the key within the Secret’s data.MaxLength: 253
MinLength: 1
Pattern: ^[-._a-zA-Z0-9]+$
Required: {}

NamespacedSecretValueSource says where a value set by the cluster-scoped EngineClass comes from: a Secret in a namespace the platform controls.

Appears in:

FieldDescriptionDefaultValidation
secretKeyRef NamespacedSecretKeyReferencesecretKeyRef selects the Secret key that holds the value.Required: {}

NativeTrackerSettings is the policy of the engine’s own tracker. It maps onto Crewlet’s tracker.native.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
inboxRetentionDays integerinboxRetentionDays 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 is where the engine may connect to, beyond DNS and its own namespace.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
exceptCIDRs string arrayexceptCIDRs 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 arrayto 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: {}

Underlying type: string

NetworkPolicyMode is whether the operator restricts traffic to the engine.

Validation:

  • Enum: [Isolated None]

Appears in:

FieldDescription
IsolatedNetworkPolicyIsolated 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.
NoneNetworkPolicyNone creates no NetworkPolicy.

NetworkPolicyPeer is the pods its podSelector selects in the namespaces its namespaceSelector selects, as a NetworkPolicy peer that sets both.

Appears in:

FieldDescriptionDefaultValidation
namespaceSelector LabelSelectornamespaceSelector 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 LabelSelectorpodSelector selects pods in those namespaces by their labels. Unset
selects every pod in them.
Optional: {}

NetworkPolicySettings is the NetworkPolicy the operator puts around each company’s engine pods.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
mode NetworkPolicyModemode is whether the operator restricts the engine’s traffic.IsolatedEnum: [Isolated None]
Optional: {}
apiConsumers NetworkPolicyPeer arrayapiConsumers 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 NetworkPolicyEgressegress 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: {}

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:

FieldDescription
NATSObjectBackendNATS keeps files in a bucket on the company’s own event
stream, on the data volume.
S3ObjectBackendS3 keeps files in an S3-compatible bucket.

ObjectSettings is where a class’s companies keep their files.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
backend ObjectBackendbackend is where files are kept. Changing it does not move existing
files.
NATSEnum: [NATS S3]
Optional: {}
s3 S3ObjectSettingss3 is the bucket, for backend S3.Optional: {}

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:

FieldDescriptionDefaultValidation
name stringname 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 LLMProviderTypetype is which model API the provider speaks. Crewlet’s type.Enum: [Anthropic OpenAI OpenAICompatible CLIAgent]
Required: {}
model stringmodel is the model id requests are sent for, as the provider names it.
Crewlet’s model. Crewlet trims it of white space and refuses a
provider with nothing left, as naming no model.
MaxLength: 256
MinLength: 1
Required: {}
claudeModel ClaudeModelIDclaudeModel 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 stringbaseURL 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 booleanreasoning turns on an OpenAI reasoning model’s effort, so that
reasoningEffort is sent. Crewlet’s reasoning; type OpenAI only.
Optional: {}
reasoningEffort ReasoningEffortreasoningEffort 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 integerreasoningBudgetTokens 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 integertimeoutSeconds 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 LLMCredentialCooldownscooldowns is how long a failing key is set aside. Crewlet’s
cooldowns.
MinProperties: 1
Optional: {}
apiKeySecretRefs NamespacedSecretKeyReference arrayapiKeySecretRefs are the provider’s API keys, rotated as an
LLMProvider’s are.
MaxItems: 16
MinItems: 1
Optional: {}

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:

FieldDescriptionDefaultValidation
name stringname 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: {}

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:

FieldDescription
Low
Medium
High
XHigh
Max

RetentionSettings is who answers for a class’s companies’ backups.

Appears in:

FieldDescriptionDefaultValidation
backupOwner stringbackupOwner 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 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:

FieldDescriptionDefaultValidation
pools string arraypools 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 arrayseats 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 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:

FieldDescriptionDefaultValidation
endpoint stringendpoint 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 stringregion 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 stringbucket 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 stringprefix 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 booleanpathStyle addresses the bucket in the URL path rather than in the host
name; MinIO and most self-hosted gateways need it.
Optional: {}

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:

FieldDescriptionDefaultValidation
path stringpath 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 SecretValueSourcevalueFrom is the Secret key holding the file’s content.Required: {}

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:

FieldDescriptionDefaultValidation
e2b E2BSandboxe2b is the remote sandbox service.Required: {}
defaultCodingAgent CodingAgentdefaultCodingAgent is the coding agent of seats that name none.
Crewlet’s default_coding_agent.
Enum: [ClaudeCode OpenCode]
Optional: {}
defaultTimeoutSeconds integerdefaultTimeoutSeconds 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 integerdefaultPauseTTLSeconds 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 integerdefaultMaxTurns 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 arraysetup is applied to every sandbox before each seat’s own steps.
Crewlet’s setup.
MaxItems: 16
Optional: {}

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:

FieldDescriptionDefaultValidation
name stringname 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 arrayfiles are written into the sandbox before the commands run. Crewlet’s
files, a credential position.
MaxItems: 16
Optional: {}
commands string arraycommands are shell commands run in order; one that exits non-zero
fails the sandbox. Crewlet’s commands. Crewlet resolves nothing in a
command: 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 arrayenv is merged into the environment of the commands and of the run.
Crewlet’s env, a credential position.
MaxItems: 32
Optional: {}
optionalKeys string arrayoptionalKeys 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 stringbrief tells the coding agent what this step made true about the
sandbox.
MaxLength: 2048
MinLength: 1
Optional: {}
timeoutSeconds integertimeoutSeconds caps each command of the step.Minimum: 1
Optional: {}

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.

FieldDescriptionDefaultValidation
apiVersion stringcrewlet.ai/v1alpha1
kind stringSchedule
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.Optional: {}
spec ScheduleSpecspec is the schedule’s desired state.Required: {}
status ScheduleStatusstatus is the schedule’s observed state.MinProperties: 1
Optional: {}

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:

FieldDescription
EachScheduleFanOutEach 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.
LeadScheduleFanOutLead 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 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:

FieldDescriptionDefaultValidation
companyRef CompanyReferencecompanyRef names the Company this schedule belongs to. Immutable.Required: {}
target ScheduleTargettarget is the seat or the unit whose schedule this is.MinProperties: 1
Required: {}
schedule stringschedule 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 stringtimeZone 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 stringprompt 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 booleansuspend keeps the schedule in the company without firing it. Unset
is false. Crewlet’s enabled, inverted.
Optional: {}
timeoutSeconds integertimeoutSeconds 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 booleancatchUp 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 is what the operator observed about a Schedule.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
conditions Condition arrayconditions 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 integerobservedGeneration is the metadata.generation this status describes.Minimum: 1
Optional: {}

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:

FieldDescriptionDefaultValidation
seatRef LocalObjectReferenceseatRef 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 LocalObjectReferenceunitRef 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 ScheduleFanOutfanOut 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.

FieldDescriptionDefaultValidation
apiVersion stringcrewlet.ai/v1alpha1
kind stringSeat
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.Optional: {}
spec SeatSpecspec is the seat’s desired state.Required: {}
status SeatStatusstatus is the seat’s observed state.MinProperties: 1
Optional: {}

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:

FieldDescriptionDefaultValidation
slackUserID stringslackUserID 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 stringmattermostUsername 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, and
never 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 stringatlassianAccount 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 Data
Center 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 stringgithubLogin is the person’s GitHub login. Crewlet’s github_login.MaxLength: 39
MinLength: 1
Pattern: ^[A-Za-z0-9-]+$
Optional: {}
gitlabUsername stringgitlabUsername 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 own
rule 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 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:

FieldDescriptionDefaultValidation
secretKeyRef SecretKeyReferencesecretKeyRef selects the Secret key that holds the value.Optional: {}
provisioned ProvisionedCredentialprovisioned is a value the engine creates and keeps, under an
Integration with provisioning Engine.
Optional: {}

SeatEnvVar is a named credential of a seat delivered as an environment variable: from a Secret, or provisioned by the engine.

Appears in:

FieldDescriptionDefaultValidation
name stringname is the variable’s name.MaxLength: 128
MinLength: 1
Pattern: ^[A-Za-z_][A-Za-z0-9_]*$
Required: {}
valueFrom SeatCredentialSourcevalueFrom is where the value comes from.MinProperties: 1
Required: {}

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:

FieldDescriptionDefaultValidation
slack SlackSeatIntegrationslack is the seat’s own Slack app.Optional: {}
github GitHubSeatIntegrationgithub is the seat’s identity on GitHub.MinProperties: 1
Optional: {}
mattermost MattermostSeatIntegrationmattermost is the seat’s own Mattermost bot.Optional: {}

SeatIntegrationsStatus is the addresses a seat’s vendor apps must use.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
slack SlackSeatStatusslack is the Slack side of the seat.MinProperties: 1
Optional: {}
github GitHubSeatStatusgithub is the GitHub side of the seat.MinProperties: 1
Optional: {}

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:

FieldDescription
AgentSeatKindAgent is an AI agent: the engine runs it, with its own inbox,
models and tools.
HumanSeatKindHuman is a person: part of the chart (a lead, an escalation
target, a colleague to mention) whom the engine never runs.

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:

FieldDescriptionDefaultValidation
default LLMProviderReference arraydefault 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 arrayreview is the chain of the reviewer that judges the executor’s work.
Crewlet’s review.
MaxItems: 8
MinItems: 1
Optional: {}
subagent LLMProviderReference arraysubagent is the chain of the short-lived workers the seat delegates
to. Crewlet’s subagent.
MaxItems: 8
MinItems: 1
Optional: {}
auxiliary LLMProviderReference arrayauxiliary is the chain of the cheap model used for reflection and
summaries. Crewlet’s auxiliary.
MaxItems: 8
MinItems: 1
Optional: {}
judge LLMProviderReference arrayjudge 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 arraysandbox 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 is a seat’s pause, as the engine reports it.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
pausedBy stringpausedBy is who paused the seat, as Crewlet records the author of a
write: the seat of the person who paused it, or token: for a
token no seat is bound to. A pause the operator took reads
token:operator.
MaxLength: 256
MinLength: 1
Optional: {}
pausedAt TimepausedAt is when the seat was paused, to the second.Optional: {}
reason stringreason is why, in the pauser’s words.MaxLength: 500
MinLength: 1
Optional: {}
stopRunning booleanstopRunning is whether the pause also ended the turn the seat was on.Optional: {}

SeatPlacement is where a seat runs.

Appears in:

FieldDescriptionDefaultValidation
pool stringpool 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 is where the engine runs a seat.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
pool stringpool 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: }, which only the pool’s
pods carry, or, in a PerSeat pool, {crewlet.ai/seat: }, which
only the seat’s own pods carry.
MaxLength: 20
MinLength: 1
Optional: {}
workload stringworkload 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 stringnode 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 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 -seats--, and each seat of a PerSeat pool as -seat-- (the hash keeps the name the Company’s own in a namespace another Company shares), started only once the data pods are ready and rolled only after them. The pods serve their probes alone, on the engine’s port: a pod is ready once its engine has joined the company’s fleet and may claim seats, and a rollout replaces the next pod only then.

Appears in:

FieldDescriptionDefaultValidation
name stringname 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 SeatPoolModemode is how the pool runs its seats.SharedEnum: [Shared PerSeat]
Optional: {}
replicas integerreplicas 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.
1Maximum: 100
Minimum: 0
Optional: {}
maxConcurrentTurns integermaxConcurrentTurns 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 integerterminationGracePeriodSeconds 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 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:

FieldDescriptionDefaultValidation
maxConcurrentTurns integermaxConcurrentTurns 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 ResourceRequirementsresources are the compute resources of every seat pod’s engine
container. Unset sets none.
Optional: {}
terminationGracePeriodSeconds integerterminationGracePeriodSeconds 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 QuantityscratchSizeLimit 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: {}

Underlying type: string

SeatPoolMode is how a seat pool runs the seats placed in it.

Validation:

  • Enum: [Shared PerSeat]

Appears in:

FieldDescription
SharedSeatPoolShared 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.
PerSeatSeatPoolPerSeat runs replicas pods for each seat placed in the pool,
each holding that seat alone. It needs the class’s
seatPools.allowPerSeat.

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:

FieldDescription
ForbiddenSeatPoolsForbidden runs every seat on the data pods. A Company of the
class may declare no spec.topology.seatPools.
AllowedSeatPoolsAllowed 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 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:

FieldDescriptionDefaultValidation
policy SeatPoolPolicypolicy 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.
ForbiddenEnum: [Forbidden Allowed]
Optional: {}
allowPerSeat booleanallowPerSeat 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 integermaxPods 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 SeatPoolDefaultsdefaults size the pods of a pool that does not size its own.MinProperties: 1
Optional: {}

SeatPoolStatus is the state of one seat pool’s pods.

Appears in:

FieldDescriptionDefaultValidation
name stringname is the pool’s name.MaxLength: 20
MinLength: 1
Required: {}
mode SeatPoolModemode is how the pool runs its seats.Enum: [Shared PerSeat]
Optional: {}
replicas integerreplicas is the number of the pool’s pods, every seat’s together for
a PerSeat pool.
Minimum: 0
Optional: {}
readyReplicas integerreadyReplicas is the number of the pool’s pods that are ready.Minimum: 0
Optional: {}
updatedReplicas integerupdatedReplicas is the number of the pool’s pods that run the
current pod template.
Minimum: 0
Optional: {}
seats integerseats is the number of agent seats placed in the pool.Minimum: 0
Optional: {}

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:

FieldDescriptionDefaultValidation
codingAgent CodingAgentcodingAgent 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 integerpauseTTLSeconds 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 integermaxTurns 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 arraymcpServerRefs name the MCPServers the coding agent may use. Crewlet’s
mcp.servers.
MaxItems: 16
Optional: {}
env SeatEnvVar arrayenv 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 credential
position.
MaxItems: 32
Optional: {}
optionalKeys string arrayoptionalKeys 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 arraysetup is the seat’s own provisioning, applied after the Company’s.
Crewlet’s setup.
MaxItems: 16
Optional: {}

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:

FieldDescriptionDefaultValidation
companyRef CompanyReferencecompanyRef names the Company this seat belongs to. Immutable.Required: {}
handle stringhandle 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 SeatKindkind is whether the seat is an AI agent or a person. Crewlet’s kind.AgentEnum: [Agent Human]
Optional: {}
displayName stringdisplayName is the seat’s name as people read it, such as “Ana
(Platform Engineer)”. Unset is the handle. Crewlet’s name. It is for
reading 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 stringemail is the seat’s email address. Crewlet’s email. Each seat has its
own: 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 LocalObjectReferenceunitRef names the Unit, in this namespace, the seat belongs to. Unset
is a seat outside every unit, such as a chief executive.
Optional: {}
goal stringgoal is what the seat is for; it reaches the seat’s prompt. Crewlet’s
goal.
MaxLength: 2048
MinLength: 1
Optional: {}
backstory stringbackstory is who the seat is; it reaches the seat’s prompt. Crewlet’s
backstory.
MaxLength: 8192
MinLength: 1
Optional: {}
responsibilities string arrayresponsibilities are what the seat owns. Crewlet’s
responsibilities.
MaxItems: 32
items:MaxLength: 1024
items:MinLength: 1
Optional: {}
behavioralGuidelines string arraybehavioralGuidelines are how the seat should work. Crewlet’s
behavioral_guidelines.
MaxItems: 32
items:MaxLength: 1024
items:MinLength: 1
Optional: {}
manages ManagedReference arraymanages names the seats and units this seat manages; a unit stands
for every seat in it and below it. Crewlet’s manages, which names a
Seat 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 arrayworkers 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 TokenBudgettokenBudget caps the tokens this seat may spend per window, on top of
the Company’s caps. Crewlet’s token_budget.
MinProperties: 1
Optional: {}
llm SeatLLMllm is the model providers the seat runs on.MinProperties: 1
Optional: {}
learningEnabled booleanlearningEnabled 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 arraymcp 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 SeatSandboxsandbox gives the seat a sandbox to run code in. Unset gives it none.Optional: {}
placement SeatPlacementplacement is where the seat runs. Unset runs it in the Company’s
spec.topology.defaultSeatPool.
Optional: {}
paused booleanpaused 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 stringpauseReason 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 booleanstopRunning 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 SeatIntegrationsintegrations is the seat’s own identity on the company’s
integrations.
MinProperties: 1
Optional: {}
project stringproject 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 stringspace 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 SeatContactcontact 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 stringavailability 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 is what the operator observed about a Seat.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
conditions Condition arrayconditions 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 integerobservedGeneration is the metadata.generation this status describes.Minimum: 1
Optional: {}
handle stringhandle is the seat’s handle: spec.handle, or the metadata.name.MaxLength: 63
MinLength: 1
Optional: {}
seatID stringseatID 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 SeatPlacementStatusplacement is where the engine runs the seat. Unset for a Human seat,
which the engine does not run.
MinProperties: 1
Optional: {}
integrations SeatIntegrationsStatusintegrations 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 SeatPauseStatuspause 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: {}

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:

FieldDescription
RequiredSecondFactorRequired 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.
OptionalSecondFactorOptional 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 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:

FieldDescriptionDefaultValidation
name stringname is the variable’s name.MaxLength: 128
MinLength: 1
Pattern: ^[A-Za-z_][A-Za-z0-9_]*$
Required: {}
valueFrom SecretValueSourcevalueFrom is the Secret key the value is read from.Required: {}

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:

FieldDescriptionDefaultValidation
name stringname is the metadata.name of the Secret.MaxLength: 253
MinLength: 1
Required: {}
key stringkey is the key within the Secret’s data.MaxLength: 253
MinLength: 1
Pattern: ^[-._a-zA-Z0-9]+$
Required: {}

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:

FieldDescriptionDefaultValidation
name stringname is the metadata.name of the Secret.MaxLength: 253
MinLength: 1
Required: {}

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:

FieldDescriptionDefaultValidation
secretKeyRef SecretKeyReferencesecretKeyRef selects the Secret key that holds the value.Required: {}

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:

FieldDescriptionDefaultValidation
secondFactor SecondFactorsecondFactor 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.
RequiredEnum: [Required Optional]
Optional: {}
acceptInsecure booleanacceptInsecure 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 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:

FieldDescriptionDefaultValidation
typingStatus WorkingStatustypingStatus is when a seat shows that it is working. Unset takes
Crewlet’s default, Always. Crewlet’s typing_status.
Enum: [Always Addressed]
Optional: {}
statusPhrases StatusPhrasesstatusPhrases replaces the words the working indicator shows.
Crewlet’s status_phrases.
MinProperties: 1
Optional: {}

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:

FieldDescriptionDefaultValidation
credentialsSecretRef SecretReferencecredentialsSecretRef 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, both
credential positions. Rewriting the Secret rotates them without a
restart.
Required: {}

SlackSeatStatus is the Slack side of a seat, as the operator computed it.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
requestURL stringrequestURL is the URL the seat’s Slack app must deliver events to: its
Event Subscriptions request URL, /webhooks/slack/,
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 replaces the words a seat’s working indicator shows. Each line completes the sentence ” is …”, and one line is picked per phase. Each list maps onto the same-named list of Crewlet’s status_phrases.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
onboarding string arrayonboarding is shown during a seat’s first-turn onboarding pass.MaxItems: 32
items:MaxLength: 256
items:MinLength: 1
Optional: {}
execute string arrayexecute is shown while the seat works.MaxItems: 32
items:MaxLength: 256
items:MinLength: 1
Optional: {}
review string arrayreview is shown while the reviewer judges the seat’s work.MaxItems: 32
items:MaxLength: 256
items:MinLength: 1
Optional: {}
default string arraydefault is shown in any phase without lines of its own.MaxItems: 32
items:MaxLength: 256
items:MinLength: 1
Optional: {}

Underlying type: string

StreamMode is where a company’s event stream runs.

Validation:

  • Enum: [Embedded]

Appears in:

FieldDescription
EmbeddedStreamModeEmbedded runs NATS JetStream inside the engine process, with
its data on the data volume. An external NATS cluster is not offered in
v1alpha1.

StreamSettings is how a company’s event stream runs.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
mode StreamModemode is where the stream runs. Embedded is the only mode in v1alpha1.EmbeddedEnum: [Embedded]
Optional: {}

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:

FieldDescriptionDefaultValidation
otlpEndpoint stringotlpEndpoint is the collector’s OTLP/HTTP endpoint
(OTEL_EXPORTER_OTLP_ENDPOINT).
MaxLength: 2048
MinLength: 1
Required: {}
headersSecretRef NamespacedSecretKeyReferenceheadersSecretRef 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 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:

FieldDescriptionDefaultValidation
day integerday is the most tokens one local day, midnight to midnight, may spend.Minimum: 1
Optional: {}
week integerweek is the most tokens one ISO week, starting on Monday, may spend.Minimum: 1
Optional: {}
month integermonth is the most tokens one calendar month may spend.Minimum: 1
Optional: {}

TopologyStatus is the state of a company’s pods.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
data DataTopologyStatusdata is the state of the data pods.MinProperties: 1
Optional: {}
seatPools SeatPoolStatus arrayseatPools is the state of each seat pool’s pods.MaxItems: 8
Optional: {}

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:

FieldDescription
NativeTrackerNative is the engine’s own tracker.
JiraTrackerJira is Jira, connected by the company’s Jira Integration.
NoneTrackerNone is a company with no tracker.

TrackerSettings is which work tracker a company runs. It maps onto Crewlet’s tracker block.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
backend TrackerBackendbackend is which tracker the company runs.NativeEnum: [Native Jira None]
Optional: {}
native NativeTrackerSettingsnative 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.)

FieldDescriptionDefaultValidation
apiVersion stringcrewlet.ai/v1alpha1
kind stringUnit
metadata ObjectMetaRefer to Kubernetes API documentation for fields of metadata.Optional: {}
spec UnitSpecspec is the unit’s desired state.Required: {}
status UnitStatusstatus is the unit’s observed state.MinProperties: 1
Optional: {}

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:

FieldDescriptionDefaultValidation
companyRef CompanyReferencecompanyRef names the Company this unit belongs to. Immutable.Required: {}
displayName stringdisplayName 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; the
metadata.name is Crewlet’s id, the key a seat’s manages entry names
the 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 UnitTypetype is an informational label. Crewlet’s type.Enum: [Division Department Group Team Squad Pod Guild Chapter Unit]
Optional: {}
parentRef LocalObjectReferenceparentRef 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 LocalObjectReferenceleadRef names the Seat that leads the unit. Unset inherits the
parent’s lead. Crewlet’s lead.
Optional: {}
purpose stringpurpose is what the unit is for. Crewlet’s purpose.MaxLength: 2048
MinLength: 1
Optional: {}
goals string arraygoals are what the unit is working toward. Crewlet’s goals.MaxItems: 32
items:MaxLength: 1024
items:MinLength: 1
Optional: {}
channel stringchannel 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 arrayknowledge 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 stringproject 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 stringspace 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 arraymcp 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, a
credential 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 is what the operator observed about a Unit.

Validation:

  • MinProperties: 1

Appears in:

FieldDescriptionDefaultValidation
conditions Condition arrayconditions 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 integerobservedGeneration is the metadata.generation this status describes.Minimum: 1
Optional: {}
depth integerdepth is the unit’s distance from the top of the chart: 0 for a
top-level unit.
Minimum: 0
Optional: {}
seats integerseats is the number of Seats directly in the unit.Minimum: 0
Optional: {}

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:

FieldDescription
Division
Department
Group
Team
Squad
Pod
Guild
Chapter
Unit

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:

FieldDescriptionDefaultValidation
mode WebhookExposureModemode is how webhooks reach the engine.NoneEnum: [Gateway Ingress External None]
Optional: {}
gateway GatewayExposuregateway is the Gateways to attach to, for mode Gateway.Optional: {}
ingress IngressExposureingress is the Ingress settings, for mode Ingress.Optional: {}
external ExternalExposureexternal is where the forwarder runs, for mode External.MinProperties: 1
Optional: {}
hostname stringhostname 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://, which every vendor is told to deliver to. Prefer
{{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: {}

Underlying type: string

WebhookExposureMode is how vendors’ webhooks reach a company’s engine.

Validation:

  • Enum: [Gateway Ingress External None]

Appears in:

FieldDescription
GatewayWebhookExposureGateway routes the public hostname to the engine’s
public listener with an HTTPRoute.
IngressWebhookExposureIngress does the same with an Ingress.
ExternalWebhookExposureExternal 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.
NoneWebhookExposureNone exposes nothing; integrations that need inbound
delivery report that they are not exposed.

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:

FieldDescription
AlwaysWorkingStatusAlways shows it on every turn a chat message started.
AddressedWorkingStatusAddressed 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.