Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuration

TeamCraft is configured with environment variables; all are optional for a local test with the development database of docker-compose.yml. Every variable can also be read from a file by appending _FILE (TEAMCRAFT_OIDC_CLIENT_SECRET_FILE=/run/secrets/oidc), which is how container secrets are passed. For local development TeamCraft also reads an optional, git-ignored secrets/.env file in the working directory.

Configuration files are read on start, in this order; a variable that is already set (in the environment or by an earlier file) is kept:

FileWhen
the file named by TEAMCRAFT_ENV_FILEwhen the variable is set (e.g. a teamcraft.env outside the working directory)
secrets/.envwhen it exists in the working directory (development)
the system fileonly in package builds: its path is fixed at build time with TEAMCRAFT_SYSTEM_CONFIG (e.g. /etc/teamcraft/teamcraft.env); development builds never read one

In the Docker installation the variables go into teamcraft.env; the image sets TEAMCRAFT_BIND_ADDR=0.0.0.0:8080 and TEAMCRAFT_VAULT_DIR=/var/lib/teamcraft/vault, and docker-compose.yml sets the database connection with the password from a Docker secret (TEAMCRAFT_DB_PASSWORD_FILE=/run/secrets/db_password).

Values are validated on start; an invalid value stops the program with a message naming the variable. A TEAMCRAFT_* variable that TeamCraft does not know (usually a typo) is ignored but logged as a warning with the nearest known name (unknown environment variable … is ignored; did you mean …?; <NAME>_FILE forms are checked by NAME). A test keeps this page and the variables read by src/config.rs in sync.

Server

VariableDefaultMeaning
TEAMCRAFT_BIND_ADDR127.0.0.1:8080address to listen on (0.0.0.0:8080 to serve the network)
TEAMCRAFT_PUBLIC_URLhttp://localhost:<port>external URL: SSO redirects, CSRF origin check; for https:// also Secure cookies and Strict-Transport-Security
TEAMCRAFT_INSTANCE_NAMETeamCraftdefault header name, page titles, e-mails; administrators override it under Admin → Branding
TEAMCRAFT_LOG_FORMATtexttext or json
RUST_LOGinfo,tower_http=info,sqlx=warnlog filter

The server (teamcraft serve) logs to standard output; the other commands (migrate, user, vault, backup, …) log to standard error, so that their output can be read by scripts.

Database (PostgreSQL 16+)

VariableDefaultMeaning
TEAMCRAFT_DATABASE_URL–postgres://user:password@host:port/db; alternatively the parts below
TEAMCRAFT_DB_HOST, TEAMCRAFT_DB_PORT, TEAMCRAFT_DB_NAME, TEAMCRAFT_DB_USERlocalhost / 5432 / teamcraft / teamcraftconnection parts
DATABASE_URL–fallback for TEAMCRAFT_DATABASE_URL (the usual name in hosting platforms)
TEAMCRAFT_DB_PASSWORD–password (not needed with trust authentication or ~/.pgpass)
TEAMCRAFT_DB_SSLMODEpreferdisable, prefer, require, verify-ca, verify-full
TEAMCRAFT_DB_MAX_CONNECTIONS10pool size

Start-up waits up to 20 s for the database, then stops with the reason. Migrations run automatically (teamcraft serve --no-migrate skips them).

Files

VariableDefaultMeaning
TEAMCRAFT_VAULT_DIR./data/vaultfile vault and cached 3D previews – back it up
TEAMCRAFT_MAX_UPLOAD_MB512largest file per upload, also for chunked uploads
TEAMCRAFT_UPLOAD_CHUNK_MB16largest chunk of a chunked, resumable upload (PATCH /api/v1/uploads/…, PATCH /uploads/… of the web UI), 1–1024

Chunked uploads (Large files) hold one chunk in memory and write it to uploads/ in the vault directory, so TEAMCRAFT_MAX_UPLOAD_MB can be raised for multi-gigabyte CAD or simulation files (e.g. 20480) without more memory; a single multipart request (small files, the web UI’s New item form) still has to fit this limit as a whole, and a reverse proxy in front must allow request bodies of one chunk (client_max_body_size ≥ TEAMCRAFT_UPLOAD_CHUNK_MB) – or of the largest multipart upload. Make sure the vault’s disk has room for the unfinished uploads too: each user may hold 16 of them for 24 hours. Storage quotas per user and for the whole vault are set with the CLI, see Storage quotas.

Malware scanning

VariableDefaultMeaning
TEAMCRAFT_CLAMD_ADDR–ClamAV daemon that scans every upload: host:port (e.g. clamav:3310) or unix:/run/clamav/clamd.ctl; unset = no scan
TEAMCRAFT_CLAMD_MAX_MB25larger files are stored without a scan (logged); match clamd’s StreamMaxLength, 1–4096

With a scanner, every file is sent to clamd (INSTREAM) before it is moved into the vault – uploads, check-ins, chunked uploads, imports. Infected content is refused (400, the signature name in the message) and never stored; a chunked upload starts over. When the daemon cannot be reached, the upload is refused with 503 instead of stored unscanned. ClamAV is a separate service (e.g. the clamav/clamav image next to TeamCraft); raise its StreamMaxLength together with TEAMCRAFT_CLAMD_MAX_MB to scan large CAD files too.

Encrypted backups

VariableDefaultMeaning
TEAMCRAFT_BACKUP_PASSPHRASE–passphrase of teamcraft backup --encrypt and of restoring such a backup (at least 12 characters); without it the CLI prompts on a terminal. Prefer TEAMCRAFT_BACKUP_PASSPHRASE_FILE

See Backups. Losing the passphrase means losing the backup – keep it apart from the backups themselves.

Data retention

VariableDefaultMeaning
TEAMCRAFT_RETENTION_LATEST_GRACE_DAYS7days after which the old versions of a file set to keep only the latest version are removed (1–3650; 0 = the housekeeping never removes them, only teamcraft vault purge-versions does)
TEAMCRAFT_AUDIT_RETENTION_DAYS0days the audit log is kept; 0 = for ever, otherwise 30–36500; the removal is recorded as one audit.purge entry; entries that separation of duties still needs (edits of revisions in work or review, preparing actions of open changes) are kept until those are closed; administrator elevation entries are removed too (the elevation list keeps reason and times)
TEAMCRAFT_PREVIEW_CACHE_MAX_MB0size the preview cache (<vault>/previews) is trimmed to, least recently used first; 0 = no limit; previews are made again when needed

Files keep every version unless someone sets a file to keep only the latest version, so the defaults change nothing for existing installations. See Data retention.

3D preview limits

The 3D preview converts a file in a separate teamcraft preview-mesh process with a time limit (at most two at a time). A file above the size cap of its kind is never opened: no conversion starts, the page says it is too large for a 3D preview, and the refusal is cached (raising the cap takes effect at once). The process also runs with a memory limit; a file that needs more fails with a message instead of taking the host down. Large simulation results are stored as they are, never parsed fully – see Simulations.

VariableDefaultMeaning
TEAMCRAFT_PREVIEW_MAX_RESULT_MB64largest simulation result file (VTK, VTU, VTP, FRD) that is previewed
TEAMCRAFT_PREVIEW_MAX_MESH_MB256largest mesh or point cloud (STL, OBJ, PLY, 3MF, glTF, LAS, …)
TEAMCRAFT_PREVIEW_MAX_STEP_MB256largest STEP file (tessellation needs a multiple of the file size)
TEAMCRAFT_PREVIEW_MAX_MEMORY_MB1024address space of the preview process, 0 = unlimited

The same process limits protect the text extraction of PDF and HTML reports (teamcraft text-extract: at most 32 MB per PDF and 100 pages, the first 16 MB of an HTML file, 60 s, the memory limit below).

The memory limit (RLIMIT_AS) is enforced on Linux; on macOS the system may ignore it, and on Windows it is not enforced (the size caps and the time limit still are). Every variable also exists as NAME_FILE.

Sign-in

VariableDefaultMeaning
TEAMCRAFT_SESSION_TTL_HOURS72session lifetime
TEAMCRAFT_COOKIE_SECUREtrue for https:// public URLsforce the Secure cookie flag
TEAMCRAFT_LOCAL_LOGINtrue without SSOusername/password accounts
TEAMCRAFT_SIGNIN_MAX_FAILURES10failed password sign-ins per username in 15 minutes before 429 (5× per client address; 0 = off)
TEAMCRAFT_METRICS_TOKEN– (endpoint off)enables GET /metrics (Prometheus text format); the scraper sends this value (at least 16 characters) as Authorization: Bearer …. Request counts and latency, database pool, pending webhook deliveries, e-mails and chat messages, 3D preview queue
TEAMCRAFT_BOOTSTRAP_ADMIN_USERNAME, TEAMCRAFT_BOOTSTRAP_ADMIN_PASSWORDadmin / –create this administrator on start when there are no accounts (public servers)
TEAMCRAFT_OIDC_*–single sign-on, see Users, roles and SSO – also TEAMCRAFT_OIDC_TOKEN_IDLE_DAYS (idle lifetime of SSO users’ new tokens, 0 = off) and the back-channel logout URI
TEAMCRAFT_APPROVAL_REAUTHoffa fresh sign-in to sign off review decisions in the browser: release (every approval) or every_decision (approvals and rejections); see below

Sign-off of review decisions. With TEAMCRAFT_APPROVAL_REAUTH a reviewer confirms a decision on the change page with the account password, or – for single sign-on accounts – with Sign in again, which sends them to the identity provider with prompt=login and max_age=0; the provider’s auth_time must be at most five minutes old, and the confirmation counts for 10 minutes. API tokens are not asked: reviewing needs the approve token scope (write tokens get 403). Every decision records how it was signed off (session, password, sso or token) and an optional stated meaning (“approved as design owner”), shown on the change page, in GET /api/v1/changes/{number} and kept with earlier review rounds. A wrong password counts like a failed sign-in (user.password_failed, throttled); a fresh SSO sign-in writes user.reauthenticate.

Failed password sign-ins are counted per username and per client address for 15 minutes from the first failure; when a counter is full the sign-in page answers 429 Too Many Requests with Retry-After – even for the right password – until the 15 minutes have passed. A successful sign-in clears the username’s counter. The counters live in the memory of each server process (a restart clears them). Behind a reverse proxy on the same host or an internal network, the client address is the last X-Forwarded-For entry, the one the proxy added; a client that talks to the server directly is counted by its own address. Sign-in, failed sign-in and sign-out are in the audit log (user.sign_in, user.sign_in_failed, user.sign_out).

Notifications (optional)

VariableMeaning
TEAMCRAFT_SMTP_URLSMTP server in lettre syntax: smtps://user:password@host:465, smtp://host:587?tls=required, smtp://localhost:25
TEAMCRAFT_MAIL_FROMsender, Name <address> (required with SMTP)
TEAMCRAFT_REQUEST_DIGEST_HOURShours between two e-mail digests of the change requests waiting for triage, per CAD editor and project group (default 24, 0 = off, at most 720); only with SMTP
TEAMCRAFT_MATTERMOST_URLbase URL of the Mattermost server (https://chat.example.org, also below a path prefix); together with the bot token it switches notifications to direct messages of a bot account
TEAMCRAFT_MATTERMOST_BOT_TOKENaccess token of the bot account (secret; also as TEAMCRAFT_MATTERMOST_BOT_TOKEN_FILE). Both variables are required together
TEAMCRAFT_MATTERMOST_WEBHOOKdeprecated: incoming webhook for notifications (ignored when the bot is configured); logs a warning at start-up
TEAMCRAFT_MATTERMOST_DIRECTdeprecated, webhook only: true: direct messages through the webhook (they appear to come from the webhook’s creator), false (default): mention in the webhook’s channel – notifications about restricted project groups then show only a generic text and the link
MATTERMOST_ERROR_WEBHOOKincoming webhook that receives internal server errors (rate limited)

Mattermost: a bot account for direct messages

Notifications reach Mattermost only as a direct message to the person, never in a channel. TeamCraft signs in as a bot account and uses the REST API: it looks the user up by name (GET /api/v4/users/username/…, cached for ten minutes), opens the direct channel bot ↔ user (POST /api/v4/channels/direct) and posts (POST /api/v4/posts). In Mattermost the messages come from the bot (shown with the BOT tag), and every user has one conversation with it. A direct message can only be read by its recipient, so it carries the full title and text, also for restricted project groups – unless the group switched notification content off, then only a generic text and the link are sent.

Set up the bot once:

  1. In Mattermost: System Console → Integrations → Integration Management: Enable Bot Account Creation must be on.
  2. Integrations → Bot Accounts → Add Bot Account: username e.g. teamcraft, display name TeamCraft. A bot needs no role beyond Member and no channel or team membership: it only has to read user profiles and open direct messages, which every account may do. Do not give it a system role.
  3. Create a token for the bot (Create New Token), keep it in a file that only the server reads, and set TEAMCRAFT_MATTERMOST_URL and TEAMCRAFT_MATTERMOST_BOT_TOKEN_FILE. Both are required together.
  4. Check it from Account → Notifications: switch Mattermost on, save and press Send a test (the test notification is delivered like every other).

Users enter their Mattermost username on their account page (empty = their TeamCraft login). If it is unknown or the Mattermost account is deactivated, the chat delivery of that notification is marked failed at once, with the reason (for example Mattermost user “xy” not found – check your Mattermost username) shown under Notifications; it is never posted into a channel instead. The bell and the e-mail are not affected. A rejected token (HTTP 401), a missing permission or a server error is retried like any delivery (five attempts with the usual pause) and then marked failed, with the reason.

The server URL is set by the administrator only. The client follows no redirects (the token must not travel to another host) and ignores proxy variables. The error webhook MATTERMOST_ERROR_WEBHOOK stays an ordinary channel webhook: it is for administrators, not personal.

Deprecated webhook mode. With only TEAMCRAFT_MATTERMOST_WEBHOOK set, notifications still go out as before (a mention in the webhook’s channel, or with TEAMCRAFT_MATTERMOST_DIRECT=true a direct message that appears to come from the person who created the webhook), the server logs a deprecation warning at start-up and the account page says so. Everybody in the channel reads the mentions, which is why restricted groups show only a generic text there. See Upgrading.

The change request digest is an e-mail per project group to its CAD editors and admins with the requests raised since the previous digest that are still New, and how many older ones still wait for triage. Nothing is sent when no new request came in. Every user can mute it on the account page (E-mail digest of new change requests …). The server remembers per user and group up to when the digests reached (table request_digests), so a restart or a second server never sends a period twice; the e-mail goes through the same outbox, retries and access checks as every notification.

Event webhooks

Administrators register outgoing webhooks on the web page Webhooks or through the API (Event webhooks). These variables limit where they may send to:

VariableDefaultMeaning
TEAMCRAFT_WEBHOOK_ALLOWED_HOSTS–comma separated host names, IP addresses or *.domain; when set, webhooks can only target these hosts, and these may be internal
TEAMCRAFT_WEBHOOK_ALLOW_PRIVATEfalsetrue: every host may resolve to private, loopback or link-local addresses (single-network installations, development)
TEAMCRAFT_WEBHOOK_RETENTION_DAYS30sent and failed deliveries are removed after this many days (1–3650)

By default webhooks reach public addresses only. An on-premises ERP or CI server is internal, so list it: TEAMCRAFT_WEBHOOK_ALLOWED_HOSTS=erp.corp.example,ci.corp.example.

Assistant (optional)

The built-in assistant (Ask TeamCraft) is off until an API key is configured, or, for a local model server, until the provider openai-compatible and its base URL are set. While it is off the buttons are hidden and /assistant and POST /api/v1/assistant answer 404. Every variable also works as NAME_FILE (the file’s contents).

VariableDefaultMeaning
TEAMCRAFT_ASSISTANT_PROVIDERanthropicwire format: anthropic (Messages API), openai (OpenAI and Azure OpenAI v1, Chat Completions) or openai-compatible (Ollama, vLLM, LM Studio, Mistral, OpenRouter, Groq …)
TEAMCRAFT_ASSISTANT_BASE_URLhttps://api.anthropic.com/v1 / https://api.openai.com/v1API base (/messages or /chat/completions is added). Required for openai-compatible, e.g. http://ollama.internal:11434/v1; Azure: https://<resource>.openai.azure.com/openai/v1
TEAMCRAFT_ASSISTANT_API_KEY–the key. A secret: prefer _FILE, it is never logged. Optional for openai-compatible (local servers)
TEAMCRAFT_ANTHROPIC_API_KEY–older name of TEAMCRAFT_ASSISTANT_API_KEY, still accepted. Setting both with different values is an error
TEAMCRAFT_ASSISTANT_MODELclaude-opus-5-5 (anthropic)model id, or the Azure deployment name. Required for openai and openai-compatible
TEAMCRAFT_ASSISTANT_MAX_STEPS12most model calls (tool rounds) per question, 1–50
TEAMCRAFT_ASSISTANT_MAX_TOKENS16000output tokens per model call, 256–200000
TEAMCRAFT_ASSISTANT_REQUEST_TIMEOUT180seconds for one HTTP call, 5–3600 (a model on a CPU may need more)
TEAMCRAFT_ASSISTANT_RUN_TIMEOUT240 (at least the request timeout)seconds for a whole question, at least the request timeout
TEAMCRAFT_ASSISTANT_MAX_CONCURRENT4questions running at the same time on the server, 1–64
TEAMCRAFT_ASSISTANT_INTERNAL_URLS–comma or space separated base URLs of internal / self-hosted model servers (http(s)://host[:port][/path], no credentials). Project groups that switched external_llm off allow the assistant only when TEAMCRAFT_ASSISTANT_BASE_URL is one of them or below one (same scheme, host and port, path prefix at a segment boundary)
TEAMCRAFT_ASSISTANT_RETENTION_DAYS30days an idle assistant conversation (one per user, text of questions and answers only) is kept before it is deleted, 1–365

With only TEAMCRAFT_ANTHROPIC_API_KEY (and optionally the model and the steps) everything works as it did before these variables existed. The startup log shows assistant=<provider>:<model>@<host>, never the key.

Where the questions go, and what is done about the key:

  • The base URL comes only from this configuration, never from users, the admin pages or anything a model or tool returns. Internal hosts are allowed on purpose, so a model server inside the network works (the webhook protection against internal addresses is for URLs that users enter and is not used here).
  • Redirects are not followed. An answer that redirects is an error, so the key is never sent to a second host. A user name or password in the URL, a query and a non-http(s) scheme are rejected at startup.
  • A warning is logged at startup when a key would be sent over plain http to a host that is not this computer (localhost, 127.0.0.0/8, ::1). Use https for anything else.
  • The server honours HTTPS_PROXY / NO_PROXY. A firewall with an egress allow-list must let the server reach the API host.

Check the setup with teamcraft assistant check (run it with the same environment as the server; it needs no database). It sends one small request with one tool and reports whether the server is reachable, the key is accepted, the model exists, the model calls the tool and the server reports token counts. Many local models are served without tool support: this is how you find out before your users do. A server that reports no token counts still works, but the token limit of a run cannot count its calls (the step and time limits still apply, and the audit record says usage_reported: false). The check never prints the key.

Fixed limits per question: 800 000 tokens in total. Each question is recorded in the audit log (assistant.run: user, quick action, question length, provider, model, tools used, token counts, usage_reported, the page kind and identifiers, whether it was asked in the conversation and the outcome – cancelled when the client closed the connection before the answer – never the question or the answer).

Local agents

The desktop app can run an AI agent on the user’s own computer (its Agent view, see ACP agents), and users can connect other MCP clients (an assistant set up by hand, the teamcraft mcp bridge) with a personal access token. Such agents send the user’s questions and the TeamCraft data they look up to the agent’s own AI provider, under the user’s own account and terms.

Company AI instead of shadow AI. For data-loss prevention an organisation can turn local agents off and offer its own AI centrally: the provider configured under Assistant – Anthropic, OpenAI or Azure OpenAI with the company’s contract and key, or a model server inside the network (Ollama, vLLM …). Users then work with Ask TeamCraft in the web UI and with the Agent view of the desktop app, which runs on that assistant (Company AI); the key stays on the server and never reaches a client. Every question runs with the user’s rights, is recorded in the audit log (assistant.run, without the question or the answer) and is bounded by the assistant’s limits (steps, tokens, time, questions at the same time). Admin → AI (/admin/ai) shows the setting, the MCP endpoint’s state and the configured provider, model, host and limits – never the key, only whether one is set.

VariableDefaultMeaning
TEAMCRAFT_LOCAL_AGENTSallowedallowed or off. off: the MCP endpoint is closed for every token and the desktop app’s Agent view runs on the company AI (the assistant), or says that AI is off when none is configured. Any other value stops the server at startup

Like every variable it also works as TEAMCRAFT_LOCAL_AGENTS_FILE. The startup log shows local_agents=allowed|off. Changing it needs a restart of the server; the desktop app picks it up at its next sign-in or window reload and checks it again before every agent start.

What off does:

  • POST /api/v1/mcp answers every call with 403 and a JSON-RPC error naming this setting, whoever sends it and with whichever token (administrators included): the desktop app’s agent, the teamcraft mcp bridge, an agent the user set up by hand, an older desktop app. Without a valid token the answer stays 401. The built-in assistant is not affected: it calls the same tools inside the server, not over this endpoint. Refusals are not written to the audit log (they change nothing).
  • GET /api/v1/me reports capabilities.local_agents: false and capabilities.mcp: false. The desktop app then ends an agent that is still running and refuses to start one (in the app’s Rust code, not only in the user interface). Its Agent view – the app’s one place for AI – runs on the company AI instead: with an assistant configured (TEAMCRAFT_ASSISTANT_*), questions go to the server’s assistant automatically, with no local option shown (the key never reaches the app); without one the view says that AI is switched off by the administrator. Settings → Agents shows the same explanation. A desktop app older than this setting still offers its local agent, but the agent gets no TeamCraft tools: the endpoint refuses it.
  • The desktop app marks the MCP connection it hands to a local agent with the header X-TeamCraft-Client: desktop-agent. It only picks the wording of the refusal; leaving it out does not get a call through.

What off does not do – it is cooperative enforcement, not a barrier against a determined user: it does not close the REST API (/api/v1/…) to a user’s own personal access token. A program the user writes, or another MCP client or agent that wraps the REST API with that token, still reads and writes with that user’s rights and can hand what it reads to an AI provider of the user’s choice. Nor can a server stop anyone from copying what they see into another tool. The complement is scoped personal access tokens: give an agent a read_only or mcp_only token (see API reference). A written usage policy, the token list of each user (Account → API tokens, revocable by administrators) and the audit log (writes are recorded under the user’s name) are the controls for the rest.

Tests

VariableMeaning
TEAMCRAFT_TEST_DATABASE_URLserver for the integration tests (default: the configuration above); each test creates and drops its own teamcraft_test_* database
TEAMCRAFT_REQUIRE_DB_TESTSfail instead of skipping when no database is reachable (CI)
TEAMCRAFT_REQUIRE_PG_TOOLSfail instead of skipping the backup/restore test when pg_dump/pg_restore are missing or older than the server (CI)
TEAMCRAFT_WRITE_SIM_FIXTURES1 lets the ignored test write_sim_fixtures regenerate tests/fixtures/sim (developers only)

MCP stdio bridge (client side)

Only teamcraft mcp, the bridge for AI assistants that run on a user’s machine, reads these. The server does not (see MCP server).

VariableMeaning
TEAMCRAFT_SERVERbase URL of the TeamCraft server (default http://localhost:8080)
TEAMCRAFT_TOKENthe user’s personal access token (or --token-file); it is never printed