From 8b25af9c53737eac37b0b8e0425f9cac0563eb22 Mon Sep 17 00:00:00 2001 From: pinotelio Date: Fri, 30 Oct 2026 12:18:45 -0700 Subject: [PATCH] docs: name the assistant Ask Crewlet The engine's in-dashboard assistant is now named Ask Crewlet. Rename it in the API types' doc comments, and so in the CRD descriptions, the chart's CRDs and the generated API reference, and in the guides, the concepts and CONTRIBUTING. The CEL message for an enabled assistant without llm names it too. Field names, JSON keys and every other contract stay as they were. Signed-off-by: pinotelio --- CONTRIBUTING.md | 2 +- api/v1alpha1/company_types.go | 32 ++++++------- api/v1alpha1/engineclass_types.go | 6 +-- api/v1alpha1/llmprovider_types.go | 8 ++-- config/crd/bases/crewlet.ai_companies.yaml | 16 +++---- .../crd/bases/crewlet.ai_engineclasses.yaml | 6 +-- config/crd/bases/crewlet.ai_llmproviders.yaml | 2 +- .../templates/crd/companies.crewlet.ai.yaml | 16 +++---- .../crd/engineclasses.crewlet.ai.yaml | 6 +-- .../crd/llmproviders.crewlet.ai.yaml | 2 +- docs/concepts/company-document.md | 4 +- docs/concepts/runtime.md | 6 +-- docs/guides/cli-agents.md | 24 +++++----- docs/guides/exposure.md | 4 +- docs/reference/api.md | 46 +++++++++---------- test/crd/company_test.go | 2 +- 16 files changed, 91 insertions(+), 91 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bf8f65c5..693417af 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -320,7 +320,7 @@ which engine pod's boxes dial their tool bridge on loopback `(*Bridge).Reaches` in `internal/api/mcpbridge/mcpbridge.go`) to `internal/controller/company_workload.go`, which gives every engine pod the Company's public address as `CREWLET_MCP_BRIDGE_URL` for the runs placed in -E2B and the Dashboard Assistant's deep work alone, to +E2B and Ask Crewlet's deep work alone, to `internal/render/bootstrap.go`, which binds a seat pod's `api.port` on every interface so that its own `Direct` boxes reach it on loopback, to `internal/controller/company_exposure.go`, which under `Isolated` lets the diff --git a/api/v1alpha1/company_types.go b/api/v1alpha1/company_types.go index 25458697..f65492ac 100644 --- a/api/v1alpha1/company_types.go +++ b/api/v1alpha1/company_types.go @@ -165,28 +165,28 @@ type CompanyLLMSettings struct { UsePlatformProviders *bool `json:"usePlatformProviders,omitempty"` } -// CompanyAssistant is whether the company runs the Dashboard Assistant, the -// models it runs on and the bounds of one turn. It maps onto Crewlet's +// CompanyAssistant is whether the company runs Ask Crewlet, the models it +// runs on and the bounds of one turn. It maps onto Crewlet's // `assistant` block, each field onto the field it names. // -// The assistant answers a signed-in person's questions about the company and +// Ask Crewlet answers a signed-in person's questions about the company and // prepares changes for that person to approve, acting only as them: every // read is a request of theirs, and nothing is written until they approve. // Every provider in llm must drive a CLI Crewlet runs with no tool of its // own (ClaudeCode or Pi; Codex keeps a shell its sandbox only confines, and -// OpenCode's has not been measured to go), with webTools Denied: the -// assistant runs it in the engine's pod, never as a seat's executor runs. Crewlet refuses any other in the dry run before every apply, and +// OpenCode's has not been measured to go), with webTools Denied: Ask +// Crewlet runs it in the engine's pod, never as a seat's executor runs. Crewlet refuses any other in the dry run before every apply, and // the refusal is reported on the Company, since the rule turns on the // providers' own specs. // +kubebuilder:validation:MinProperties=1 -// +kubebuilder:validation:XValidation:rule="!has(self.enabled) || !self.enabled || (has(self.llm) && size(self.llm) > 0)",message="an enabled assistant needs llm: name the model provider it runs on, one whose webTools is Denied",fieldPath=".llm" +// +kubebuilder:validation:XValidation:rule="!has(self.enabled) || !self.enabled || (has(self.llm) && size(self.llm) > 0)",message="Ask Crewlet, when enabled, needs llm: name the model provider it runs on, one whose webTools is Denied",fieldPath=".llm" type CompanyAssistant struct { - // enabled runs the assistant. Unset or false leaves it off. Crewlet's + // enabled runs Ask Crewlet. Unset or false leaves it off. Crewlet's // `enabled`. // +optional Enabled *bool `json:"enabled,omitempty"` - // llm is the assistant's model chain, the first provider tried first, + // llm is Ask Crewlet's model chain, the first provider tried first, // referred to as a Seat's chain is. Required when enabled is true. // Crewlet's `llm`. // +optional @@ -224,27 +224,27 @@ type CompanyAssistant struct { // +kubebuilder:validation:Maximum=365 RetentionDays int32 `json:"retentionDays,omitempty"` - // tokenBudget caps the tokens each person's assistant may spend per + // tokenBudget caps the tokens Ask Crewlet may spend for each person per // window, charged on top of the company's own spec.tokenBudget. // Crewlet's `token_budget`. // +optional TokenBudget TokenBudget `json:"tokenBudget,omitzero"` - // deepWork lets the assistant hand a large task (research, scripts, + // deepWork lets Ask Crewlet hand a large task (research, scripts, // files, many steps) to a coding CLI running its own tools in a box of - // its own, which needs spec.sandbox. Unset, the assistant answers in + // its own, which needs spec.sandbox. Unset, Ask Crewlet answers in // quick mode only. Crewlet's `deep_work`. // +optional DeepWork CompanyAssistantDeepWork `json:"deepWork,omitzero"` } -// CompanyAssistantDeepWork is the Dashboard Assistant's deep work: the model -// a large task is handed to and the bounds of one run. It maps onto Crewlet's +// CompanyAssistantDeepWork is Ask Crewlet's deep work: the model a large +// task is handed to and the bounds of one run. It maps onto Crewlet's // `assistant.deep_work` block, each field onto the field it names. // // A deep-work run is Claude Code in its own harness, with its shell, its // files and its web tools: the point of the escalation. Its one way into -// Crewlet is the signed-in person's own assistant tools over the tool +// Crewlet is the signed-in person's own Ask Crewlet tools over the tool // bridge, so every read is still that person's request and every write still // a proposal they approve. The provider llm names must drive ClaudeCode: // Crewlet confines a deep-work run on the engine pod around that one CLI's @@ -869,7 +869,7 @@ type CompanyExposure struct { // coding runs call the engine back on, overriding the one the class's // webhooks.hostname derives. A seat's executor run in E2B calls the // engine's tool bridge there, and exports its traces there while the - // class sends telemetry, and the Dashboard Assistant's deep work calls + // class sends telemetry, and Ask Crewlet's deep work calls // the bridge there wherever it runs; a seat's Direct run, on a data pod // or a seat pod, dials its own pod's listener on loopback for both. // Required @@ -1215,7 +1215,7 @@ type CompanySpec struct { // +optional LLM CompanyLLMSettings `json:"llm,omitzero"` - // assistant is the company's Dashboard Assistant. Unset leaves it off. + // assistant configures Ask Crewlet. Unset leaves it off. // Crewlet's `assistant`. // +optional Assistant CompanyAssistant `json:"assistant,omitzero"` diff --git a/api/v1alpha1/engineclass_types.go b/api/v1alpha1/engineclass_types.go index c262b5b5..44f504b7 100644 --- a/api/v1alpha1/engineclass_types.go +++ b/api/v1alpha1/engineclass_types.go @@ -198,7 +198,7 @@ type DataPodSettings struct { // resumes or its pause TTL expires (the Seat's pauseTTLSeconds, else the // Company's spec.sandbox.defaultPauseTTLSeconds, 1800 seconds unless // set; 0 removes the box at once). It holds the confined box of each - // Dashboard Assistant deep-work run placed on the pod too, in a + // Ask Crewlet deep-work run placed on the pod too, in a // directory of its own. A box is removed when its run ends, and holds // the run's checkout, its coding CLI's home and temporary files, and // whatever the run installs and builds. A pod whose boxes @@ -607,7 +607,7 @@ const ( // WebhookExposure is how vendors' webhooks, and the calls coding runs make // back to the engine, reach a company's engine: the tool bridge calls and the -// traces of a seat's executor run in E2B, and the Dashboard Assistant's deep +// traces of a seat's executor run in E2B, and Ask Crewlet's deep // work's calls, a seat's Direct run dialling its own engine pod on loopback // instead. Whatever the mode, they // reach the engine's public listener (Crewlet's api.public), a port of its @@ -894,7 +894,7 @@ type NetworkPolicySettings struct { // code host and the package registries it installs from are reached // from the pod; it calls its tools and sends its traces to its own pod's // listener on loopback, which no policy polices. A data pod also calls - // the Company's public address, for the Dashboard Assistant's deep work, + // the Company's public address, for Ask Crewlet's deep work, // which Crewlet holds to it in whichever cell it runs. A call that lands // on the public route's proxies inside the cluster is admitted by a rule // of the data pods' own, naming the webhooks route's proxy namespaces or diff --git a/api/v1alpha1/llmprovider_types.go b/api/v1alpha1/llmprovider_types.go index ee0a0202..c6e87b8c 100644 --- a/api/v1alpha1/llmprovider_types.go +++ b/api/v1alpha1/llmprovider_types.go @@ -38,9 +38,9 @@ const ( // `denied`). // // A seat keeps its CLI's web tools: it must not have less reach than the -// same CLI at a terminal. A provider the Company's Dashboard Assistant runs -// on turns them off, which Crewlet requires of every model in -// spec.assistant.llm: the assistant reads only what the signed-in person's +// same CLI at a terminal. A provider Ask Crewlet runs on turns +// them off, which Crewlet requires of every model in +// spec.assistant.llm: Ask Crewlet reads only what the signed-in person's // own requests return, and a page the model fetched for itself is text no // authority decision saw. Crewlet turns them off only for a CLI whose profile // carries a measured way to (its web_denial): ClaudeCode, Codex, OpenCode and @@ -270,7 +270,7 @@ type LLMProviderSettings struct { // webTools is whether the CLI keeps its own web tools. Unset is // Allowed, every seat's default. Denied is required of every provider - // the Company's Dashboard Assistant runs on (spec.assistant.llm), and + // Ask Crewlet runs on (spec.assistant.llm), and // is refused for a CLI Crewlet has no way to turn the web off for: it // takes ClaudeCode, Codex, OpenCode or Pi. Crewlet's // `overrides.web_tools`. diff --git a/config/crd/bases/crewlet.ai_companies.yaml b/config/crd/bases/crewlet.ai_companies.yaml index bcbede65..047a7951 100644 --- a/config/crd/bases/crewlet.ai_companies.yaml +++ b/config/crd/bases/crewlet.ai_companies.yaml @@ -72,15 +72,15 @@ spec: properties: assistant: description: |- - assistant is the company's Dashboard Assistant. Unset leaves it off. + assistant configures Ask Crewlet. Unset leaves it off. Crewlet's `assistant`. minProperties: 1 properties: deepWork: description: |- - deepWork lets the assistant hand a large task (research, scripts, + deepWork lets Ask Crewlet hand a large task (research, scripts, files, many steps) to a coding CLI running its own tools in a box of - its own, which needs spec.sandbox. Unset, the assistant answers in + its own, which needs spec.sandbox. Unset, Ask Crewlet answers in quick mode only. Crewlet's `deep_work`. properties: llm: @@ -137,12 +137,12 @@ spec: type: object enabled: description: |- - enabled runs the assistant. Unset or false leaves it off. Crewlet's + enabled runs Ask Crewlet. Unset or false leaves it off. Crewlet's `enabled`. type: boolean llm: description: |- - llm is the assistant's model chain, the first provider tried first, + llm is Ask Crewlet's model chain, the first provider tried first, referred to as a Seat's chain is. Required when enabled is true. Crewlet's `llm`. items: @@ -201,7 +201,7 @@ spec: type: integer tokenBudget: description: |- - tokenBudget caps the tokens each person's assistant may spend per + tokenBudget caps the tokens Ask Crewlet may spend for each person per window, charged on top of the company's own spec.tokenBudget. Crewlet's `token_budget`. minProperties: 1 @@ -236,7 +236,7 @@ spec: type: object x-kubernetes-validations: - fieldPath: .llm - message: 'an enabled assistant needs llm: name the model provider + message: 'Ask Crewlet, when enabled, needs llm: name the model provider it runs on, one whose webTools is Denied' rule: '!has(self.enabled) || !self.enabled || (has(self.llm) && size(self.llm) > 0)' @@ -588,7 +588,7 @@ spec: coding runs call the engine back on, overriding the one the class's webhooks.hostname derives. A seat's executor run in E2B calls the engine's tool bridge there, and exports its traces there while the - class sends telemetry, and the Dashboard Assistant's deep work calls + class sends telemetry, and Ask Crewlet's deep work calls the bridge there wherever it runs; a seat's Direct run, on a data pod or a seat pod, dials its own pod's listener on loopback for both. Required diff --git a/config/crd/bases/crewlet.ai_engineclasses.yaml b/config/crd/bases/crewlet.ai_engineclasses.yaml index 79b2a5f0..be82e747 100644 --- a/config/crd/bases/crewlet.ai_engineclasses.yaml +++ b/config/crd/bases/crewlet.ai_engineclasses.yaml @@ -227,7 +227,7 @@ spec: resumes or its pause TTL expires (the Seat's pauseTTLSeconds, else the Company's spec.sandbox.defaultPauseTTLSeconds, 1800 seconds unless set; 0 removes the box at once). It holds the confined box of each - Dashboard Assistant deep-work run placed on the pod too, in a + Ask Crewlet deep-work run placed on the pod too, in a directory of its own. A box is removed when its run ends, and holds the run's checkout, its coding CLI's home and temporary files, and whatever the run installs and builds. A pod whose boxes @@ -1368,7 +1368,7 @@ spec: code host and the package registries it installs from are reached from the pod; it calls its tools and sends its traces to its own pod's listener on loopback, which no policy polices. A data pod also calls - the Company's public address, for the Dashboard Assistant's deep work, + the Company's public address, for Ask Crewlet's deep work, which Crewlet holds to it in whichever cell it runs. A call that lands on the public route's proxies inside the cluster is admitted by a rule of the data pods' own, naming the webhooks route's proxy namespaces or @@ -1953,7 +1953,7 @@ spec: description: |- webTools is whether the CLI keeps its own web tools. Unset is Allowed, every seat's default. Denied is required of every provider - the Company's Dashboard Assistant runs on (spec.assistant.llm), and + Ask Crewlet runs on (spec.assistant.llm), and is refused for a CLI Crewlet has no way to turn the web off for: it takes ClaudeCode, Codex, OpenCode or Pi. Crewlet's `overrides.web_tools`. diff --git a/config/crd/bases/crewlet.ai_llmproviders.yaml b/config/crd/bases/crewlet.ai_llmproviders.yaml index 4e10215a..b1feb282 100644 --- a/config/crd/bases/crewlet.ai_llmproviders.yaml +++ b/config/crd/bases/crewlet.ai_llmproviders.yaml @@ -381,7 +381,7 @@ spec: description: |- webTools is whether the CLI keeps its own web tools. Unset is Allowed, every seat's default. Denied is required of every provider - the Company's Dashboard Assistant runs on (spec.assistant.llm), and + Ask Crewlet runs on (spec.assistant.llm), and is refused for a CLI Crewlet has no way to turn the web off for: it takes ClaudeCode, Codex, OpenCode or Pi. Crewlet's `overrides.web_tools`. diff --git a/dist/chart/templates/crd/companies.crewlet.ai.yaml b/dist/chart/templates/crd/companies.crewlet.ai.yaml index 8fb5f15c..5fd22561 100644 --- a/dist/chart/templates/crd/companies.crewlet.ai.yaml +++ b/dist/chart/templates/crd/companies.crewlet.ai.yaml @@ -75,15 +75,15 @@ spec: properties: assistant: description: |- - assistant is the company's Dashboard Assistant. Unset leaves it off. + assistant configures Ask Crewlet. Unset leaves it off. Crewlet's `assistant`. minProperties: 1 properties: deepWork: description: |- - deepWork lets the assistant hand a large task (research, scripts, + deepWork lets Ask Crewlet hand a large task (research, scripts, files, many steps) to a coding CLI running its own tools in a box of - its own, which needs spec.sandbox. Unset, the assistant answers in + its own, which needs spec.sandbox. Unset, Ask Crewlet answers in quick mode only. Crewlet's `deep_work`. properties: llm: @@ -140,12 +140,12 @@ spec: type: object enabled: description: |- - enabled runs the assistant. Unset or false leaves it off. Crewlet's + enabled runs Ask Crewlet. Unset or false leaves it off. Crewlet's `enabled`. type: boolean llm: description: |- - llm is the assistant's model chain, the first provider tried first, + llm is Ask Crewlet's model chain, the first provider tried first, referred to as a Seat's chain is. Required when enabled is true. Crewlet's `llm`. items: @@ -204,7 +204,7 @@ spec: type: integer tokenBudget: description: |- - tokenBudget caps the tokens each person's assistant may spend per + tokenBudget caps the tokens Ask Crewlet may spend for each person per window, charged on top of the company's own spec.tokenBudget. Crewlet's `token_budget`. minProperties: 1 @@ -239,7 +239,7 @@ spec: type: object x-kubernetes-validations: - fieldPath: .llm - message: 'an enabled assistant needs llm: name the model provider + message: 'Ask Crewlet, when enabled, needs llm: name the model provider it runs on, one whose webTools is Denied' rule: '!has(self.enabled) || !self.enabled || (has(self.llm) && size(self.llm) > 0)' @@ -591,7 +591,7 @@ spec: coding runs call the engine back on, overriding the one the class's webhooks.hostname derives. A seat's executor run in E2B calls the engine's tool bridge there, and exports its traces there while the - class sends telemetry, and the Dashboard Assistant's deep work calls + class sends telemetry, and Ask Crewlet's deep work calls the bridge there wherever it runs; a seat's Direct run, on a data pod or a seat pod, dials its own pod's listener on loopback for both. Required diff --git a/dist/chart/templates/crd/engineclasses.crewlet.ai.yaml b/dist/chart/templates/crd/engineclasses.crewlet.ai.yaml index 231367f6..527d1888 100644 --- a/dist/chart/templates/crd/engineclasses.crewlet.ai.yaml +++ b/dist/chart/templates/crd/engineclasses.crewlet.ai.yaml @@ -230,7 +230,7 @@ spec: resumes or its pause TTL expires (the Seat's pauseTTLSeconds, else the Company's spec.sandbox.defaultPauseTTLSeconds, 1800 seconds unless set; 0 removes the box at once). It holds the confined box of each - Dashboard Assistant deep-work run placed on the pod too, in a + Ask Crewlet deep-work run placed on the pod too, in a directory of its own. A box is removed when its run ends, and holds the run's checkout, its coding CLI's home and temporary files, and whatever the run installs and builds. A pod whose boxes @@ -1371,7 +1371,7 @@ spec: code host and the package registries it installs from are reached from the pod; it calls its tools and sends its traces to its own pod's listener on loopback, which no policy polices. A data pod also calls - the Company's public address, for the Dashboard Assistant's deep work, + the Company's public address, for Ask Crewlet's deep work, which Crewlet holds to it in whichever cell it runs. A call that lands on the public route's proxies inside the cluster is admitted by a rule of the data pods' own, naming the webhooks route's proxy namespaces or @@ -1956,7 +1956,7 @@ spec: description: |- webTools is whether the CLI keeps its own web tools. Unset is Allowed, every seat's default. Denied is required of every provider - the Company's Dashboard Assistant runs on (spec.assistant.llm), and + Ask Crewlet runs on (spec.assistant.llm), and is refused for a CLI Crewlet has no way to turn the web off for: it takes ClaudeCode, Codex, OpenCode or Pi. Crewlet's `overrides.web_tools`. diff --git a/dist/chart/templates/crd/llmproviders.crewlet.ai.yaml b/dist/chart/templates/crd/llmproviders.crewlet.ai.yaml index 75b7c366..b7bfae98 100644 --- a/dist/chart/templates/crd/llmproviders.crewlet.ai.yaml +++ b/dist/chart/templates/crd/llmproviders.crewlet.ai.yaml @@ -384,7 +384,7 @@ spec: description: |- webTools is whether the CLI keeps its own web tools. Unset is Allowed, every seat's default. Denied is required of every provider - the Company's Dashboard Assistant runs on (spec.assistant.llm), and + Ask Crewlet runs on (spec.assistant.llm), and is refused for a CLI Crewlet has no way to turn the web off for: it takes ClaudeCode, Codex, OpenCode or Pi. Crewlet's `overrides.web_tools`. diff --git a/docs/concepts/company-document.md b/docs/concepts/company-document.md index b5e6b112..cbf7cd90 100644 --- a/docs/concepts/company-document.md +++ b/docs/concepts/company-document.md @@ -127,8 +127,8 @@ names that the document does not hold blocks the document, as a seat's does, because Crewlet refuses such a chain where `llm_order` would only drop the key. An `LLMProvider`'s `webTools: Denied` becomes its entry's `overrides: {web_tools: denied}`, the one profile override the API offers; -Crewlet requires it of every provider the assistant runs on -([Running Seats on a Coding CLI](../guides/cli-agents.md#a-provider-for-the-dashboard-assistant)). +Crewlet requires it of every provider Ask Crewlet runs on +([Running Seats on a Coding CLI](../guides/cli-agents.md#a-provider-for-ask-crewlet)). Its `deepWork` becomes the block's `deep_work`, whose `llm` names one provider's key the same way and blocks the document when the document does not hold it; the API requires `spec.sandbox` beside it, so every deep-work diff --git a/docs/concepts/runtime.md b/docs/concepts/runtime.md index 70131359..88d83aee 100644 --- a/docs/concepts/runtime.md +++ b/docs/concepts/runtime.md @@ -221,7 +221,7 @@ over. limit bounds: a run that filled it would stop the store and the broker. Every other place an engine pod writes is bounded, so a run that writes without end is stopped at its own pod and never fills the node's disk. -- **A deep-work run's too.** The Dashboard Assistant's deep work, when it +- **A deep-work run's too.** Ask Crewlet's deep work, when it runs on the data pod rather than in `E2B`, is a confined box Crewlet makes on this volume, in a directory of its own beside the seats' boxes (`/var/lib/crewlet-sandboxes/assistant`), so `data.sandboxSizeLimit` @@ -655,7 +655,7 @@ The public address is also where a coding run calls the engine back: seat runs, which reaches Crewlet's bridge at the fleet's address, the same on every node, the data pod a call reaches relaying it over the broker to the pod holding the run's seat, a seat pod included (see [Seat - pools](../guides/cli-agents.md#seat-pools)); and the Dashboard Assistant's + pools](../guides/cli-agents.md#seat-pools)); and Ask Crewlet's deep work, which Crewlet holds to the fleet's address wherever it runs, a `Direct` run on the data pod included. The data pods must therefore be able to reach the public address: under `networkPolicy: Isolated` the @@ -749,7 +749,7 @@ proxies or forwarders), and every address but the cloud metadata endpoints and the class's `networkPolicy.egress.exceptCIDRs`, where the cluster's own networks belong ([Network policy](../guides/exposure.md#network-policy)). The route's proxies are there because a data pod calls the Company's own -public address, for the Dashboard Assistant's deep work, and inside the +public address, for Ask Crewlet's deep work, and inside the cluster that call usually lands on a proxy's pod without leaving it, where an address outside `exceptCIDRs` does not admit it. diff --git a/docs/guides/cli-agents.md b/docs/guides/cli-agents.md index e93ac931..4c153eb8 100644 --- a/docs/guides/cli-agents.md +++ b/docs/guides/cli-agents.md @@ -934,19 +934,19 @@ Seat's `Ready`). One thing a data pod does for a CLI a seat pod cannot do: above gives a key variable) or, for Hermes, Pi or OpenCode, its model provider's key in `env`, or place the seat in `data`. -## A provider for the Dashboard Assistant +## A provider for Ask Crewlet -A seat keeps its CLI's own web tools. The Company's Dashboard Assistant -(`spec.assistant`) does not: it reads only what the signed-in person's own +A seat keeps its CLI's own web tools. Ask Crewlet (configured under +`spec.assistant`) does not: it reads only what the signed-in person's own requests return, so Crewlet requires every provider in `spec.assistant.llm` to drive a CLI Crewlet runs with no tool of its own (no shell, no file reader, no tool server but the engine's own, which serves the person's -assistant tools), with its web tools off. The assistant runs its providers in +Ask Crewlet tools), with its web tools off. Ask Crewlet runs its providers in the engine's pod, as a seat's phases but the executor run, so a provider's `runIn` means nothing to it. Today that is `ClaudeCode` or `Pi`: `Codex` keeps a shell its read-only sandbox only confines, and `OpenCode`'s deny-all policy has not been measured to take its -tools away, so both are refused for the assistant though either may still +tools away, so both are refused for Ask Crewlet though either may still turn its web off for a seat. `webTools: Denied` turns them off, and renders as the entry's `overrides: {web_tools: denied}`: @@ -975,7 +975,7 @@ for: `ClaudeCode`, `Codex`, `OpenCode` and `Pi`. Every other CLI's profile carries no measured web denial, and Crewlet refuses the setting. A provider of its own keeps the person in the drawer from queueing behind a seat's long call, and its timeout is sized for one round rather than for a coding task. -Crewlet refuses an assistant chain naming a provider that keeps its web +Crewlet refuses an Ask Crewlet chain naming a provider that keeps its web tools, or one on a CLI that keeps a tool of its own, in the dry run before every apply, and the refusal is reported on the Company. Crewlet's [configuration reference](https://github.com/crewlet/crewlet/blob/main/docs/getting-started/configuration.md) @@ -983,17 +983,17 @@ describes the block and each bound. ### Deep work -`spec.assistant.deepWork` lets the assistant hand a large task (research, +`spec.assistant.deepWork` lets Ask Crewlet hand a large task (research, scripts, files, many steps) to a coding CLI running its own tools: its shell, its files and its web tools, which are the point of the escalation. The run -reaches Crewlet only through the signed-in person's own assistant tools, over +reaches Crewlet only through the signed-in person's own Ask Crewlet tools, over the tool bridge, so every read is still their request and every write still a -proposal they approve. Unset, the assistant answers in quick mode only. +proposal they approve. Unset, Ask Crewlet answers in quick mode only. Deep work runs on a provider driving `ClaudeCode`, an `LLMProvider` or a platform model provider: its run is confined around that CLI's own install and temporary directories, which no other CLI has been measured against. It is -a provider of its own, beside the assistant's chain, whose web tools stay on: +a provider of its own, beside Ask Crewlet's chain, whose web tools stay on: ```yaml apiVersion: crewlet.ai/v1alpha1 @@ -1055,8 +1055,8 @@ calls the person's tools back at the Company's public address, so a Company with none runs no deep work. Crewlet refuses a provider driving another CLI in the dry run before every -apply, and the refusal is reported on the Company, as the assistant chain's -is; the API cannot refuse it, since the rule turns on the provider's own +apply, and the refusal is reported on the Company, as a refusal of Ask +Crewlet's chain is; the API cannot refuse it, since the rule turns on the provider's own spec. A provider placed in `E2B` by its `runIn` in a Company with no `spec.sandbox.e2b` is refused on the LLMProvider (`SandboxPlacementNotOffered`). diff --git a/docs/guides/exposure.md b/docs/guides/exposure.md index e49ac06f..1f5a642c 100644 --- a/docs/guides/exposure.md +++ b/docs/guides/exposure.md @@ -66,8 +66,8 @@ say so. What the public listener serves depends on what the engine is given: connected is refused (`503`). - `/mcp/{token}`, the tool bridge: always. Every agent seat's executor is its coding CLI's run in a box, which calls the seat's tools back through - it ([Running seats on a coding CLI](cli-agents.md)), as the Dashboard - Assistant's deep work calls the person's, and the data pod a call reaches + it ([Running seats on a coding CLI](cli-agents.md)), as Ask + Crewlet's deep work calls the person's, and the data pod a call reaches relays it to the pod holding the run's seat, a seat pod included. A seat's box on its engine pod's own host, a `Direct` one, dials that pod's own listener on loopback and needs no route: a data pod's public listener, or diff --git a/docs/reference/api.md b/docs/reference/api.md index 25dc19f3..ec0aa653 100644 --- a/docs/reference/api.md +++ b/docs/reference/api.md @@ -343,9 +343,9 @@ providers.llm entry's overrides (Allowed is `allowed`, Denied is `denied`). A seat keeps its CLI's web tools: it must not have less reach than the -same CLI at a terminal. A provider the Company's Dashboard Assistant runs -on turns them off, which Crewlet requires of every model in -spec.assistant.llm: the assistant reads only what the signed-in person's +same CLI at a terminal. A provider Ask Crewlet runs on turns +them off, which Crewlet requires of every model in +spec.assistant.llm: Ask Crewlet reads only what the signed-in person's own requests return, and a page the model fetched for itself is text no authority decision saw. Crewlet turns them off only for a CLI whose profile carries a measured way to (its web_denial): ClaudeCode, Codex, OpenCode and @@ -420,17 +420,17 @@ characters overflows its pods' controller-revision-hash label. -CompanyAssistant is whether the company runs the Dashboard Assistant, the -models it runs on and the bounds of one turn. It maps onto Crewlet's +CompanyAssistant is whether the company runs Ask Crewlet, the models it +runs on and the bounds of one turn. It maps onto Crewlet's `assistant` block, each field onto the field it names. -The assistant answers a signed-in person's questions about the company and +Ask Crewlet answers a signed-in person's questions about the company and prepares changes for that person to approve, acting only as them: every read is a request of theirs, and nothing is written until they approve. Every provider in llm must drive a CLI Crewlet runs with no tool of its own (ClaudeCode or Pi; Codex keeps a shell its sandbox only confines, and -OpenCode's has not been measured to go), with webTools Denied: the -assistant runs it in the engine's pod, never as a seat's executor runs. Crewlet refuses any other in the dry run before every apply, and +OpenCode's has not been measured to go), with webTools Denied: Ask +Crewlet runs it in the engine's pod, never as a seat's executor runs. Crewlet refuses any other in the dry run before every apply, and the refusal is reported on the Company, since the rule turns on the providers' own specs. @@ -442,27 +442,27 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `enabled` _boolean_ | enabled runs the assistant. Unset or false leaves it off. Crewlet's
`enabled`. | | Optional: \{\}
| -| `llm` _[LLMProviderReference](#llmproviderreference) array_ | llm is the assistant's model chain, the first provider tried first,
referred to as a Seat's chain is. Required when enabled is true.
Crewlet's `llm`. | | MaxItems: 8
Optional: \{\}
| +| `enabled` _boolean_ | enabled runs Ask Crewlet. Unset or false leaves it off. Crewlet's
`enabled`. | | Optional: \{\}
| +| `llm` _[LLMProviderReference](#llmproviderreference) array_ | llm is Ask Crewlet's model chain, the first provider tried first,
referred to as a Seat's chain is. Required when enabled is true.
Crewlet's `llm`. | | MaxItems: 8
Optional: \{\}
| | `maxSteps` _integer_ | maxSteps is the most tool steps one turn may take. Unset takes
Crewlet's default of 30. Crewlet's `max_steps`. | | Maximum: 40
Minimum: 1
Optional: \{\}
| | `turnTimeoutSeconds` _integer_ | turnTimeoutSeconds is the longest one turn may run. Unset takes
Crewlet's default of 900. Crewlet's `turn_timeout_seconds`. | | Maximum: 1200
Minimum: 30
Optional: \{\}
| | `proposalTTLSeconds` _integer_ | proposalTTLSeconds is how long a proposed change waits for its
owner's approval. Unset takes Crewlet's default of 900. Crewlet's
`proposal_ttl_seconds`. | | Maximum: 3600
Minimum: 60
Optional: \{\}
| | `retentionDays` _integer_ | retentionDays is how long a person's conversations are kept. Unset
takes Crewlet's default of 30. Crewlet's `retention_days`. | | Maximum: 365
Minimum: 1
Optional: \{\}
| -| `tokenBudget` _[TokenBudget](#tokenbudget)_ | tokenBudget caps the tokens each person's assistant may spend per
window, charged on top of the company's own spec.tokenBudget.
Crewlet's `token_budget`. | | MinProperties: 1
Optional: \{\}
| -| `deepWork` _[CompanyAssistantDeepWork](#companyassistantdeepwork)_ | deepWork lets the assistant hand a large task (research, scripts,
files, many steps) to a coding CLI running its own tools in a box of
its own, which needs spec.sandbox. Unset, the assistant answers in
quick mode only. Crewlet's `deep_work`. | | Optional: \{\}
| +| `tokenBudget` _[TokenBudget](#tokenbudget)_ | tokenBudget caps the tokens Ask Crewlet may spend for each person per
window, charged on top of the company's own spec.tokenBudget.
Crewlet's `token_budget`. | | MinProperties: 1
Optional: \{\}
| +| `deepWork` _[CompanyAssistantDeepWork](#companyassistantdeepwork)_ | deepWork lets Ask Crewlet hand a large task (research, scripts,
files, many steps) to a coding CLI running its own tools in a box of
its own, which needs spec.sandbox. Unset, Ask Crewlet answers in
quick mode only. Crewlet's `deep_work`. | | Optional: \{\}
| #### CompanyAssistantDeepWork -CompanyAssistantDeepWork is the Dashboard Assistant's deep work: the model -a large task is handed to and the bounds of one run. It maps onto Crewlet's +CompanyAssistantDeepWork is Ask Crewlet's deep work: the model a large +task is handed to and the bounds of one run. It maps onto Crewlet's `assistant.deep_work` block, each field onto the field it names. A deep-work run is Claude Code in its own harness, with its shell, its files and its web tools: the point of the escalation. Its one way into -Crewlet is the signed-in person's own assistant tools over the tool +Crewlet is the signed-in person's own Ask Crewlet tools over the tool bridge, so every read is still that person's request and every write still a proposal they approve. The provider llm names must drive ClaudeCode: Crewlet confines a deep-work run on the engine pod around that one CLI's @@ -542,7 +542,7 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | -| `publicBaseURL` _string_ | publicBaseURL is the HTTPS address vendors deliver webhooks to and
coding runs call the engine back on, overriding the one the class's
webhooks.hostname derives. A seat's executor run in E2B calls the
engine's tool bridge there, and exports its traces there while the
class sends telemetry, and the Dashboard Assistant's deep work calls
the bridge there wherever it runs; a seat's Direct run, on a data pod
or a seat pod, dials its own pod's listener on loopback for both.
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, and
its CREWLET_MCP_BRIDGE_URL on every engine pod, with its
CREWLET_SANDBOX_OTEL_RECEIVER_URL while the class sends telemetry,
which the engine reads only at start: changing it restarts the data
pod and the seat pods.
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: \{\}
| +| `publicBaseURL` _string_ | publicBaseURL is the HTTPS address vendors deliver webhooks to and
coding runs call the engine back on, overriding the one the class's
webhooks.hostname derives. A seat's executor run in E2B calls the
engine's tool bridge there, and exports its traces there while the
class sends telemetry, and Ask Crewlet's deep work calls
the bridge there wherever it runs; a seat's Direct run, on a data pod
or a seat pod, dials its own pod's listener on loopback for both.
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, and
its CREWLET_MCP_BRIDGE_URL on every engine pod, with its
CREWLET_SANDBOX_OTEL_RECEIVER_URL while the class sends telemetry,
which the engine reads only at start: changing it restarts the data
pod and the seat pods.
Its host is a name, an IPv4
address or an IPv6 address in brackets, followed by at most one port,
1 to 65535: Crewlet refuses to start on any other, but for an IPv6
address whose zone holds a ']' (https://[fe80::1%25eth0]]/), which it
starts on and no vendor reaches. The API judges the host and the port
itself rather than leaving them to the API server's URL parser, which
is Go's net/url as the API server was built and is run: it takes such
a zone, and under Go's GODEBUG setting urlstrictcolons=0
https://h.example:80:80 too. | | MaxLength: 2048
MinLength: 1
Optional: \{\}
| | `dashboardBaseURL` _string_ | dashboardBaseURL is where a browser reaches the engine: its dashboard,
and the sign-in of the company's people. It overrides the address of
the class's API route: set it when the class routes no API, or people
reach it through something in front of the route (a single sign-on
proxy, say). Crewlet's api.external_url, in the data pod's
crewlet.yaml, which the engine reads only at start: changing it
restarts the data pod. The engine takes from it the origin a person's
write must come from, whether the session cookie is Secure (https)
and its scope, and the base of every link a person follows: a link an
agent composes, an invitation (/dashboard#/invite/...), a password
link. An address other than the route's must serve the engine, its
/dashboard and its /auth routes included. The route, when the class
has one, stays an origin the engine accepts. It is never the public
address: the public listener serves no dashboard. A trailing '/' is
dropped.
Crewlet compares the origin of a person's write with this address as a
browser spells it, and refuses to start on an address whose host a
browser rewrites before it sends it, so the API refuses it too: a host
outside ASCII, as it is or percent-encoded (write its xn-- form,
https://xn--bcher-kva.example for https://bücher.example), a host
whose last label is a number and that is not an IPv4 address of four
decimal octets (127.1, 2130706433, 0x7f.0.0.1, 192.168.010.1,
crewlet.123: write 127.0.0.1, or a name that ends in a word), and an
IPv6 address with a zone ([fe80::1%25eth0]). Its host is a name, an
IPv4 address or an IPv6 address in brackets, followed by at most one
port, 1 to 65535 (http://[::1]:8080, not http://::1:8080), which the
API judges itself, as for publicBaseURL. | | MaxLength: 2048
MinLength: 1
Optional: \{\}
| | `artifactsBaseURL` _string_ | artifactsBaseURL is where a browser reaches the artifact origin,
ahead of the class's artifacts route: a tunnel, or http://localhost:8082
for a browser that port-forwards it. Crewlet's api.artifacts.external_url;
changing it restarts the data pod. https, or http on localhost or
127.x.x.x; \{artifact\} at the start of the host gives each artifact a host
of its own. It may not be the dashboard's or the public listener's
origin, nor a parent of either's host (RuntimeReady=False AddressRefused). | | MaxLength: 2048
MinLength: 1
Optional: \{\}
| @@ -668,7 +668,7 @@ _Appears in:_ | `knowledge` _[KnowledgeSettings](#knowledgesettings)_ | knowledge is which knowledge base the company runs. | | MinProperties: 1
Optional: \{\}
| | `tokenBudget` _[TokenBudget](#tokenbudget)_ | tokenBudget caps the tokens all seats together may spend per window.
Each window binds every agent seat, so Crewlet refuses one below
turn_engine.executor_min_budget_tokens (25000 unless spec.engineConfig
sets turn_engine): an executor launch needs that much of every window
left, and a seat under a smaller ceiling would never launch one. The
refusal comes from the engine's dry run, Invalid on the Company.
Crewlet's `token_budget`. | | MinProperties: 1
Optional: \{\}
| | `llm` _[CompanyLLMSettings](#companyllmsettings)_ | llm is how the company chooses among its model providers. | | MinProperties: 1
Optional: \{\}
| -| `assistant` _[CompanyAssistant](#companyassistant)_ | assistant is the company's Dashboard Assistant. Unset leaves it off.
Crewlet's `assistant`. | | MinProperties: 1
Optional: \{\}
| +| `assistant` _[CompanyAssistant](#companyassistant)_ | assistant configures Ask Crewlet. Unset leaves it off.
Crewlet's `assistant`. | | MinProperties: 1
Optional: \{\}
| | `embeddings` _[EmbeddingSettings](#embeddingsettings)_ | embeddings is the provider vectors are computed with. Unset leaves
search keyword-only. Crewlet's providers.embeddings. | | Optional: \{\}
| | `sandbox` _[SandboxSettings](#sandboxsettings)_ | sandbox is where the company's agent seats' executors run. Required
of a company with an Agent seat and a model provider, which Crewlet
refuses without it (SandboxRequired). Crewlet's providers.sandbox. | | Optional: \{\}
| | `integrations` _[CompanyIntegrationSettings](#companyintegrationsettings)_ | integrations is company-wide integration behaviour. | | MinProperties: 1
Optional: \{\}
| @@ -862,7 +862,7 @@ _Appears in:_ | `startupSeconds` _integer_ | startupSeconds is how long a data pod's engine may take, from its
start, to answer /health 200: the time it takes to recover what it holds
on its volume (the store, the event stream, the replicated estate) and
bring its broker up. Crewlet waits that recovery out rather than
bounding it, because it grows with the data, so the startup probe is
what bounds it: it allows at least this long from the container's
start, and less than ten seconds more. A boot that runs past it is
restarted and begins its recovery again, so err long: a window that is
too long costs nothing on a healthy boot, only the time to restart one
that hung.
It is at least every bound Crewlet puts on a data pod's boot, laid end
to end, which a window may not cut short: 1866 seconds, or 2006 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. One of them grows with
what the node holds and is left to the recovery's share, as the
recovery is: the claim of each batch of a seat pod's events the node
kept and could not settle, 15 s a batch. 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, and only then reads the company's secrets, starts its tool
servers and restores its CLIs' logins.
Changing it changes the data pods' template, which restarts them. | | Maximum: 86400
Minimum: 1866
Optional: \{\}
| | `terminationGracePeriodSeconds` _integer_ | terminationGracePeriodSeconds is how long a data pod may take to stop.
The engine finishes the turn segments it runs in its own process
before it exits (a seat's launch, the collection of its run, the
review, a delegated worker) and puts no bound on that itself, so the
default is five minutes, which covers a long segment, rather than the
Kubernetes default of thirty seconds, which does not. A seat's
executor run is not waited for: a Direct one on the pod is a process
of it and ends with it, its box with the pod's sandboxes volume, and
Crewlet carries its round on in a fresh run once the pod is back, and
an E2B one carries on in its sandbox. | 300 | Maximum: 3600
Minimum: 30
Optional: \{\}
| | `scratchSizeLimit` _[Quantity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.37/#quantity-resource-api)_ | scratchSizeLimit caps the emptyDir a data pod keeps its /tmp and HOME
on: what the processes the engine runs on the pod write off its data
volume, the packages and files of the stdio tool servers it starts
(a launcher such as npx or uvx installs a server under HOME), git's
and their scratch files, the sockets of its tool sessions, and what a
seat's Direct executor run writes outside its box. Crewlet points a
run's temporary directories into its box but confines it to nothing
else, so a command that names /tmp or the engine's home outright
writes here. A pod that writes more is evicted, with every run and
turn on it and the company's API; its data volume is untouched. Unset
is 10Gi.
It bounds and reserves as sandboxSizeLimit does, and the
ephemeral-storage limit in resources bounds the two together with the
container's own writes. Changing it changes the data pods' template,
which restarts them. | | Optional: \{\}
| -| `sandboxSizeLimit` _[Quantity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.37/#quantity-resource-api)_ | sandboxSizeLimit caps the emptyDir a data pod keeps its sandboxes in,
at /var/lib/crewlet-sandboxes: the boxes Crewlet makes on the pod
itself for the executor runs it places there (its direct cell, under
Crewlet's providers.sandbox.local.state_dir): one for each agent seat
of the pod whose run is running, a seat running one at a time, and one
for each run parked on a person's question, which frees its seat for
its next run and keeps its box, its processes stopped, until it
resumes or its pause TTL expires (the Seat's pauseTTLSeconds, else the
Company's spec.sandbox.defaultPauseTTLSeconds, 1800 seconds unless
set; 0 removes the box at once). It holds the confined box of each
Dashboard Assistant deep-work run placed on the pod too, in a
directory of its own. A box is removed when its run ends, and holds
the run's checkout, its coding CLI's home and temporary files, and
whatever the run installs and builds. A pod whose boxes
write more is evicted, with every run and turn on it; its data volume
is untouched. Unset is 20Gi. It bounds the boxes alone: what a run
writes outside its box counts against scratchSizeLimit, or, under
/var/lib/crewlet, against the data volume.
It bounds the boxes and reserves nothing: the scheduler places the
pod by the ephemeral-storage request in resources, and an
ephemeral-storage limit there bounds the container's own writes and
every emptyDir of the pod together, so give it room for this one.
Changing it changes the data pods' template, which restarts them. | | Optional: \{\}
| +| `sandboxSizeLimit` _[Quantity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.37/#quantity-resource-api)_ | sandboxSizeLimit caps the emptyDir a data pod keeps its sandboxes in,
at /var/lib/crewlet-sandboxes: the boxes Crewlet makes on the pod
itself for the executor runs it places there (its direct cell, under
Crewlet's providers.sandbox.local.state_dir): one for each agent seat
of the pod whose run is running, a seat running one at a time, and one
for each run parked on a person's question, which frees its seat for
its next run and keeps its box, its processes stopped, until it
resumes or its pause TTL expires (the Seat's pauseTTLSeconds, else the
Company's spec.sandbox.defaultPauseTTLSeconds, 1800 seconds unless
set; 0 removes the box at once). It holds the confined box of each
Ask Crewlet deep-work run placed on the pod too, in a
directory of its own. A box is removed when its run ends, and holds
the run's checkout, its coding CLI's home and temporary files, and
whatever the run installs and builds. A pod whose boxes
write more is evicted, with every run and turn on it; its data volume
is untouched. Unset is 20Gi. It bounds the boxes alone: what a run
writes outside its box counts against scratchSizeLimit, or, under
/var/lib/crewlet, against the data volume.
It bounds the boxes and reserves nothing: the scheduler places the
pod by the ephemeral-storage request in resources, and an
ephemeral-storage limit there bounds the container's own writes and
every emptyDir of the pod together, so give it room for this one.
Changing it changes the data pods' template, which restarts them. | | Optional: \{\}
| #### DataStorage @@ -2070,7 +2070,7 @@ _Appears in:_ | `model` _string_ | model is the model the CLI runs, in the CLI's own grammar: an alias
or an id for ClaudeCode (`sonnet`, `claude-opus-5-5`), an OpenAI id
for Codex, `/` for OpenCode. 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: \{\}
| | `timeoutSeconds` _integer_ | timeoutSeconds bounds one stretch of the CLI's model work, wall clock,
with no call of a seat's tool in flight: from the CLI's launch, or the
answer to its last tool call, to its next tool call or its end, the
model's answer and the CLI's own retries in it. It is not a bound on
a run of the CLI, which asks the model many times and calls the
seat's tools between: a tool call stops the clock however long it
takes (a delegation, a slow tool server), and the next stretch starts
afresh. Unset takes Crewlet's default of 600, the ceiling Anthropic
documents for one answer of a current Claude model at its full
output. A timeout is retryable, so a seat's chain moves on to its
next provider. It bounds the phases the CLI runs in the engine's
process (the reviewer, delegated workers, the summariser, the judge);
a seat's executor run on the provider, its CLI's own run in a box, is
bounded by its round cap instead (the Company's
spec.sandbox.defaultMaxTurns and the Seat's spec.sandbox.maxTurns).
Crewlet's `timeout_seconds`. | | Minimum: 1
Optional: \{\}
| | `maxConcurrent` _integer_ | maxConcurrent is how many of the provider's CLI processes run at once
in each engine pod; each takes 200 to 450 MB of the pod's memory,
OpenCode's at the top of that range (docs/guides/cli-agents.md). One
process lives for a whole run of the CLI, many model requests and
tool calls long, and holds its place for all of it, so this is also
how many seats' runs the provider has going at once in a pod: a run
past it waits for a place. A model call made on the same provider
from inside one of a run's tool calls (a delegated worker's) borrows
the run's place rather than wait for another, which the runs holding
every place could leave it waiting for forever. Unset takes
Crewlet's default of 4. A seat's executor run takes none: it is a
process of its own box, and a seat runs one at a time. Crewlet's
`max_concurrent`. | | Maximum: 64
Minimum: 1
Optional: \{\}
| -| `webTools` _[CLIAgentWebTools](#cliagentwebtools)_ | webTools is whether the CLI keeps its own web tools. Unset is
Allowed, every seat's default. Denied is required of every provider
the Company's Dashboard Assistant runs on (spec.assistant.llm), and
is refused for a CLI Crewlet has no way to turn the web off for: it
takes ClaudeCode, Codex, OpenCode or Pi. Crewlet's
`overrides.web_tools`. | | Enum: [Allowed Denied]
Optional: \{\}
| +| `webTools` _[CLIAgentWebTools](#cliagentwebtools)_ | webTools is whether the CLI keeps its own web tools. Unset is
Allowed, every seat's default. Denied is required of every provider
Ask Crewlet runs on (spec.assistant.llm), and
is refused for a CLI Crewlet has no way to turn the web off for: it
takes ClaudeCode, Codex, OpenCode or Pi. Crewlet's
`overrides.web_tools`. | | Enum: [Allowed Denied]
Optional: \{\}
| #### LLMProviderSpec @@ -2134,7 +2134,7 @@ _Appears in:_ | `model` _string_ | model is the model the CLI runs, in the CLI's own grammar: an alias
or an id for ClaudeCode (`sonnet`, `claude-opus-5-5`), an OpenAI id
for Codex, `/` for OpenCode. 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: \{\}
| | `timeoutSeconds` _integer_ | timeoutSeconds bounds one stretch of the CLI's model work, wall clock,
with no call of a seat's tool in flight: from the CLI's launch, or the
answer to its last tool call, to its next tool call or its end, the
model's answer and the CLI's own retries in it. It is not a bound on
a run of the CLI, which asks the model many times and calls the
seat's tools between: a tool call stops the clock however long it
takes (a delegation, a slow tool server), and the next stretch starts
afresh. Unset takes Crewlet's default of 600, the ceiling Anthropic
documents for one answer of a current Claude model at its full
output. A timeout is retryable, so a seat's chain moves on to its
next provider. It bounds the phases the CLI runs in the engine's
process (the reviewer, delegated workers, the summariser, the judge);
a seat's executor run on the provider, its CLI's own run in a box, is
bounded by its round cap instead (the Company's
spec.sandbox.defaultMaxTurns and the Seat's spec.sandbox.maxTurns).
Crewlet's `timeout_seconds`. | | Minimum: 1
Optional: \{\}
| | `maxConcurrent` _integer_ | maxConcurrent is how many of the provider's CLI processes run at once
in each engine pod; each takes 200 to 450 MB of the pod's memory,
OpenCode's at the top of that range (docs/guides/cli-agents.md). One
process lives for a whole run of the CLI, many model requests and
tool calls long, and holds its place for all of it, so this is also
how many seats' runs the provider has going at once in a pod: a run
past it waits for a place. A model call made on the same provider
from inside one of a run's tool calls (a delegated worker's) borrows
the run's place rather than wait for another, which the runs holding
every place could leave it waiting for forever. Unset takes
Crewlet's default of 4. A seat's executor run takes none: it is a
process of its own box, and a seat runs one at a time. Crewlet's
`max_concurrent`. | | Maximum: 64
Minimum: 1
Optional: \{\}
| -| `webTools` _[CLIAgentWebTools](#cliagentwebtools)_ | webTools is whether the CLI keeps its own web tools. Unset is
Allowed, every seat's default. Denied is required of every provider
the Company's Dashboard Assistant runs on (spec.assistant.llm), and
is refused for a CLI Crewlet has no way to turn the web off for: it
takes ClaudeCode, Codex, OpenCode or Pi. Crewlet's
`overrides.web_tools`. | | Enum: [Allowed Denied]
Optional: \{\}
| +| `webTools` _[CLIAgentWebTools](#cliagentwebtools)_ | webTools is whether the CLI keeps its own web tools. Unset is
Allowed, every seat's default. Denied is required of every provider
Ask Crewlet runs on (spec.assistant.llm), and
is refused for a CLI Crewlet has no way to turn the web off for: it
takes ClaudeCode, Codex, OpenCode or Pi. Crewlet's
`overrides.web_tools`. | | Enum: [Allowed Denied]
Optional: \{\}
| | `runIn` _[SandboxPlacement](#sandboxplacement)_ | runIn is where a seat's executor run launched on the provider happens:
Direct, a process of the engine pod that holds the seat, or E2B, the
Company's E2B sandbox, which spec.sandbox.e2b must then configure.
Unset takes the Company's spec.sandbox.defaultRunIn. It is read
wherever a seat's executor can launch on the provider: as the first
ClaudeCode or OpenCode member of its executor chain, and as a later
one a launch falls back to while the members before it sit out their
spent plans, so each run is placed by the member it runs on. Only
ClaudeCode and OpenCode take it, as only they run an executor.
Crewlet's `run_in`. | | Enum: [Direct E2B]
Optional: \{\}
| | `auth` _[CLIAgentAuth](#cliagentauth)_ | auth is how the CLI signs in. Crewlet's `auth`. | | MinProperties: 1
Required: \{\}
| | `env` _[SecretEnvVar](#secretenvvar) array_ | env is extra environment of the CLI, in every phase a seat runs on the
provider, its executor run included. In the engine's pod 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, such as the
address of a gateway a CLI reads from its environment (ClaudeCode's
ANTHROPIC_BASE_URL). It is how Hermes, Pi and OpenCode sign in under
auth mode Subscription or Env with no login of their own: their model
provider's key, under a name Crewlet reads as a credential, such as
OPENROUTER_API_KEY. Under auth mode Env it is the whole sign-in of
ClaudeCode too: a gateway's ANTHROPIC_AUTH_TOKEN, or a cloud
provider's switch (CLAUDE_CODE_USE_BEDROCK, CLAUDE_CODE_USE_VERTEX,
CLAUDE_CODE_USE_FOUNDRY) with that provider's credentials, names it may
set under no other mode, which hands the CLI a credential of its own
beside them. 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), nor TZ, as Crewlet hands every CLI
the engine's own zone and reads its limit resets in it. Under auth mode
Subscription it may
not set a variable Crewlet sets there to sign the CLI in with its
seat's login either: GeminiCLI's GOOGLE_GENAI_USE_GCA.
A seat's executor run on the provider, Direct or E2B, gets all of env,
beneath the Seat's own spec.sandbox.env, which wins a name: a
gateway's address and the bearer token it takes, a cloud switch such
as CLAUDE_CODE_USE_BEDROCK and its region, a proxy, so the run reaches
its model as the provider's other phases do. So under auth mode Env,
env signs an E2B run in as it signs the provider's other phases in. A
Seat whose spec.sandbox.env signs ClaudeCode in itself
keeps every sign-in of the provider's out of its runs, and the rest of
env in them. Crewlet's `env`, a credential position. | | MaxItems: 32
Optional: \{\}
| @@ -2727,7 +2727,7 @@ _Appears in:_ | --- | --- | --- | --- | | `mode` _[NetworkPolicyMode](#networkpolicymode)_ | mode is whether the operator restricts the engine's traffic. | Isolated | Enum: [Isolated None]
Optional: \{\}
| | `apiConsumers` _[NetworkPolicyPeer](#networkpolicypeer) array_ | apiConsumers are the pods admitted to the engine's API port besides
the operator and the Gateway proxies or Ingress controller of the
class's API route, and to nothing else of the engine (the public
port, which the webhooks reach, admits only where they arrive from):
the platform's own components (a control plane, a dashboard) that
call the engines of this class's companies. Each holds an access
token, which the engine still requires. | | MaxItems: 16
MinItems: 1
Optional: \{\}
| -| `egress` _[NetworkPolicyEgress](#networkpolicyegress)_ | egress narrows where the engine may connect to. The engine runs code
the tenant supplies in its pod (stdio MCP servers, coding CLIs, and
what its agents have them do), so under Isolated its pods may reach
DNS, the pods of their own namespace, and every address outside the
cluster except the cloud metadata endpoints (169.254.169.254,
fd00:ec2::254), which hand out the node's credentials. What else is in
the cluster is unreachable only if listed in exceptCIDRs. A seat's
Direct executor run is a process of the engine pod, so it egresses
under this policy, its box's setup commands included: its vendor, its
code host and the package registries it installs from are reached
from the pod; it calls its tools and sends its traces to its own pod's
listener on loopback, which no policy polices. A data pod also calls
the Company's public address, for the Dashboard Assistant's deep work,
which Crewlet holds to it in whichever cell it runs. A call that lands
on the public route's proxies inside the cluster is admitted by a rule
of the data pods' own, naming the webhooks route's proxy namespaces or
the class's external forwarders; a load balancer the call leaves the
cluster through must stay outside exceptCIDRs. An E2B run happens in
the Company's E2B sandbox, which this policy does not reach. | | MinProperties: 1
Optional: \{\}
| +| `egress` _[NetworkPolicyEgress](#networkpolicyegress)_ | egress narrows where the engine may connect to. The engine runs code
the tenant supplies in its pod (stdio MCP servers, coding CLIs, and
what its agents have them do), so under Isolated its pods may reach
DNS, the pods of their own namespace, and every address outside the
cluster except the cloud metadata endpoints (169.254.169.254,
fd00:ec2::254), which hand out the node's credentials. What else is in
the cluster is unreachable only if listed in exceptCIDRs. A seat's
Direct executor run is a process of the engine pod, so it egresses
under this policy, its box's setup commands included: its vendor, its
code host and the package registries it installs from are reached
from the pod; it calls its tools and sends its traces to its own pod's
listener on loopback, which no policy polices. A data pod also calls
the Company's public address, for Ask Crewlet's deep work,
which Crewlet holds to it in whichever cell it runs. A call that lands
on the public route's proxies inside the cluster is admitted by a rule
of the data pods' own, naming the webhooks route's proxy namespaces or
the class's external forwarders; a load balancer the call leaves the
cluster through must stay outside exceptCIDRs. An E2B run happens in
the Company's E2B sandbox, which this policy does not reach. | | MinProperties: 1
Optional: \{\}
| #### ObjectBackend @@ -2819,7 +2819,7 @@ _Appears in:_ | `model` _string_ | model is the model the CLI runs, in the CLI's own grammar: an alias
or an id for ClaudeCode (`sonnet`, `claude-opus-5-5`), an OpenAI id
for Codex, `/` for OpenCode. 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: \{\}
| | `timeoutSeconds` _integer_ | timeoutSeconds bounds one stretch of the CLI's model work, wall clock,
with no call of a seat's tool in flight: from the CLI's launch, or the
answer to its last tool call, to its next tool call or its end, the
model's answer and the CLI's own retries in it. It is not a bound on
a run of the CLI, which asks the model many times and calls the
seat's tools between: a tool call stops the clock however long it
takes (a delegation, a slow tool server), and the next stretch starts
afresh. Unset takes Crewlet's default of 600, the ceiling Anthropic
documents for one answer of a current Claude model at its full
output. A timeout is retryable, so a seat's chain moves on to its
next provider. It bounds the phases the CLI runs in the engine's
process (the reviewer, delegated workers, the summariser, the judge);
a seat's executor run on the provider, its CLI's own run in a box, is
bounded by its round cap instead (the Company's
spec.sandbox.defaultMaxTurns and the Seat's spec.sandbox.maxTurns).
Crewlet's `timeout_seconds`. | | Minimum: 1
Optional: \{\}
| | `maxConcurrent` _integer_ | maxConcurrent is how many of the provider's CLI processes run at once
in each engine pod; each takes 200 to 450 MB of the pod's memory,
OpenCode's at the top of that range (docs/guides/cli-agents.md). One
process lives for a whole run of the CLI, many model requests and
tool calls long, and holds its place for all of it, so this is also
how many seats' runs the provider has going at once in a pod: a run
past it waits for a place. A model call made on the same provider
from inside one of a run's tool calls (a delegated worker's) borrows
the run's place rather than wait for another, which the runs holding
every place could leave it waiting for forever. Unset takes
Crewlet's default of 4. A seat's executor run takes none: it is a
process of its own box, and a seat runs one at a time. Crewlet's
`max_concurrent`. | | Maximum: 64
Minimum: 1
Optional: \{\}
| -| `webTools` _[CLIAgentWebTools](#cliagentwebtools)_ | webTools is whether the CLI keeps its own web tools. Unset is
Allowed, every seat's default. Denied is required of every provider
the Company's Dashboard Assistant runs on (spec.assistant.llm), and
is refused for a CLI Crewlet has no way to turn the web off for: it
takes ClaudeCode, Codex, OpenCode or Pi. Crewlet's
`overrides.web_tools`. | | Enum: [Allowed Denied]
Optional: \{\}
| +| `webTools` _[CLIAgentWebTools](#cliagentwebtools)_ | webTools is whether the CLI keeps its own web tools. Unset is
Allowed, every seat's default. Denied is required of every provider
Ask Crewlet runs on (spec.assistant.llm), and
is refused for a CLI Crewlet has no way to turn the web off for: it
takes ClaudeCode, Codex, OpenCode or Pi. Crewlet's
`overrides.web_tools`. | | Enum: [Allowed Denied]
Optional: \{\}
| | `auth` _[PlatformLLMProviderAuth](#platformllmproviderauth)_ | auth is how the CLI signs in. Crewlet's `auth`. | | MinProperties: 1
Required: \{\}
| | `env` _[NamespacedSecretEnvVar](#namespacedsecretenvvar) array_ | env is extra environment of the CLI, as an LLMProvider's spec.env is,
each value read from a Secret in a namespace the platform controls:
the model provider's key Hermes, Pi or OpenCode signs in with, the
address of the platform's gateway a CLI reads from its environment
(ClaudeCode's ANTHROPIC_BASE_URL), or, under auth mode Env, the token
that gateway issued the tenant (ANTHROPIC_AUTH_TOKEN), for every phase
the provider serves. ClaudeCode's sign-in names (ANTHROPIC_AUTH_TOKEN
and the CLAUDE_CODE_USE_* switches) are refused under every other
mode. A seat's executor run on the provider gets all of it, beneath
the Seat's own spec.sandbox.env, Direct on the tenant's engine pod or
in the tenant's own E2B sandbox, the gateway's address included.
Crewlet's `env`, a credential position. | | MaxItems: 16
Optional: \{\}
| @@ -4192,7 +4192,7 @@ _Appears in:_ WebhookExposure is how vendors' webhooks, and the calls coding runs make back to the engine, reach a company's engine: the tool bridge calls and the -traces of a seat's executor run in E2B, and the Dashboard Assistant's deep +traces of a seat's executor run in E2B, and Ask Crewlet's deep work's calls, a seat's Direct run dialling its own engine pod on loopback instead. Whatever the mode, they reach the engine's public listener (Crewlet's api.public), a port of its diff --git a/test/crd/company_test.go b/test/crd/company_test.go index 19549903..d577e38e 100644 --- a/test/crd/company_test.go +++ b/test/crd/company_test.go @@ -669,7 +669,7 @@ func TestCompanyAssistantValidation(t *testing.T) { c.Spec.Assistant = a } } - const msgEnabledNeedsLLM = "an enabled assistant needs llm" + const msgEnabledNeedsLLM = "Ask Crewlet, when enabled, needs llm" cases := []createCase[*v1.Company]{ {name: "an enabled assistant is accepted", mutate: assistant(nil)}, {