nothing of yours is held by Softwerk
Your credential runs your mission, or the mission does not run.
Every mission runs on something you own. The model credential is yours, the GitHub App installation is yours, the Linear workspace is yours. The factory borrows each of them for exactly one task at a time, in a sealed envelope it cannot reuse, and writes down which one it borrowed on the run. Softwerk never holds your secret and never resells inference.
Your model credential
Connect an Anthropic API key under Settings, Connections. A mission runs on it or does not run. The refusal path is concrete: a tenant with nothing connected gets one activity on the issue saying the mission did not start, no repository claim and no model run. Softwerk's own platform key is a fallback for Softwerk's internal tenants only, and a kill switch can turn even that off. A stored OpenAI key is a connection, not a mission engine; the fleet runs missions on Anthropic credentials today.
- apps/agent/src/runner.ts decideModelCredential, refusalActivity
- apps/agent/src/credentials.ts isPlatformFallbackEnabled, assertBrokeredCredential
- cdk/config/environments.ts internalTenantIds
- apps/web/src/lib/fleet/issue-credential.ts MODEL_PROVIDER = anthropic
- apps/web/src/lib/tenant-credential.ts CREDENTIAL_PROVIDERS
The broker
The fleet holds no tenant secret at rest. Per task it asks the web app for exactly one credential over a request signed with an HMAC bound to tenant, mission and role and to a purpose (model, github or tracker). The answer comes back sealed: AES-256-GCM under an HKDF-derived key, a single-use nonce with replay protection in a Redis store, and the signed request as associated data, so a captured reply cannot be replayed for another tenant, another mission or another purpose. In production the broker refuses to issue without the replay store. Inside the executor pod the model subprocess runs as a second uid and sees only an allowlist of variables, so even the runner's environment is not the model's.
- apps/web/src/lib/fleet/issue-credential.ts CREDENTIAL_PURPOSES, replay store
- apps/web/src/lib/fleet/credential-envelope.ts sealCredentialResponse
- apps/agent/src/credential-envelope.ts openCredentialResponse
- apps/agent/src/credential-broker.ts
- tests/fleet/credential-envelope-vectors.json
- apps/agent/src/uid-split.ts
- apps/agent/src/executor.ts LLM_ENV_ALLOWLIST
- docs/runbooks/fleet-credentials.md
Ran on
Every run page states which credential it ran on: tenant API key, tenant subscription, or platform. The API exposes the same value as credentialSource. A run dispatched before the broker existed reads "not recorded" rather than guessing. The same page shows the model cost of the role turns that reported what they spent, priced against a stored rate table so an amount stays reproducible after the table changes. There is no spend cap; your Anthropic console is the cost control.
- apps/web/src/components/factory/run-detail.tsx Ran on, CREDENTIAL_SOURCE_COPY
- apps/web/prisma/schema.prisma Pipeline.credentialSource
- apps/web/src/app/api/v1/factory-runs/[id]/route.ts
- apps/worker/src/mission-cost.ts
Your GitHub App installation
The fleet never uses a personal access token. It mints a short-lived installation token per task from your own installation, scoped to the one repository the mission names, so GitHub itself refuses a repository you did not install on. Pull requests are opened by the App bot, under your installation, in your organisation.
- apps/web/src/lib/fleet/github-installation-token.ts repositoryNames, DEFINITE_REFUSAL_STATUSES
- apps/web/src/app/api/v1/connections/github/callback/route.ts
- apps/agent/src/repo-auth.ts resolveRepoAuth
- apps/agent/src/workspace.ts BROKERED_TOKEN_TTL_MS
Your Linear workspace
Map a Linear team to a repository from the Connections page; the mapping creates the factory project, so there is no second tracker to maintain. Assign or mention an issue and a mission starts. Every role's activity, every gate question and every decision lives on the issue: a state change, a reaction on the gate's own comment or a threaded reply is a gate decision. The tracker token the fleet uses to write there is your app actor token, issued per turn through the same broker.
- apps/web/src/lib/linear/provision.ts mapLinearTeamToProject
- apps/web/src/components/connections/linear-teams-card.tsx
- apps/web/src/app/api/v1/webhooks/linear/route.ts
- apps/web/src/lib/linear/gate-events.ts
- apps/web/src/lib/fleet/issue-credential.ts issueTrackerToken
Your MCP servers and plugins
Projects can register their own MCP servers over https with a tool allowlist, an egress allowlist and a Secrets Manager ARN, never a secret value, and enable plugins per project. The registry is an operator switch: it stays dormant until TENANT_SECRET_PREFIX is set for the deployment.
- apps/web/src/app/api/v1/mcp-servers/route.ts
- apps/web/src/lib/mcp-registry.ts TENANT_SECRET_PREFIX
What is stored and how
Credential values are envelope-encrypted at rest and never returned to the browser; the UI shows that a connection exists, read from the table on every request. Per-tenant data keys that can be crypto-shredded are an operator switch (PER_TENANT_DEK_ENABLED); the shipped default is the master-key envelope.
- apps/web/src/lib/tenant-credential.ts
- apps/web/src/lib/tenant-string-encryptor.ts
- apps/web/src/lib/per-tenant-dek-flag.ts PER_TENANT_DEK_ENABLED
- docs/runbooks/per-tenant-dek.md
Not live
AWS Bedrock roles, federated identity, multi-key pools with failover, and deployment into your own AWS account are planned and not live. Softwerk runs in its own AWS account today. The code accepts a subscription token as a credential and records such a run as having run on the tenant's subscription; what Softwerk offers is a mission on your own API key.
- cdk/ is the whole stack
- apps/web/src/lib/fleet/issue-credential.ts credentialSource: oauth_token is tenant_subscription
Connect a repository, a Linear team and an API key. Keep everything else.
Softwerk is not self-serve: sign-in is Google SSO on an allowlisted workspace domain, and a workspace is set up by Softwerk on request. The GitHub App and the Linear application are configured once for the whole deployment by Softwerk, not per workspace, and the app offers each connect step only when that deployment-level configuration is in place. On production today the Linear application is not yet seeded, so its connect step is not offered, and the GitHub App private key is a placeholder, so no mission can clone a repository or open a pull request yet. Once both are seeded, you connect your Anthropic key, your GitHub App installation and your Linear team, and the first mission ends in a pull request with its certificate beside it.
Book a factory walkthrough