docs / onboarding

Bootstrap, capabilities & teams

A fresh Fred deployment starts with zero admins and zero enabled tools or agents. Nothing is on by default — every capability a team ends up with is a deliberate, auditable decision by whoever holds the one secret that starts the platform.

The shortest path

Four steps get you from a fresh install to a working, team-scoped chat experience:

  1. Bootstrap yourself as the first platform admin. One call, gated on your login and the deployment's bootstrap secret. Works exactly once.
  2. Enable the tools and agent templates this deployment may run. Nothing is available platform-wide until you say so.
  3. Create a team, naming its first admin(s) in the same call. No team ever exists without an owner.
  4. Grant that team a subset of what you enabled. Its members see exactly that, and nothing else.
This is live, implemented behavior today — not a roadmap item. The sections below walk through why each step is gated the way it is.

Install with nothing enabled

A newly deployed Fred platform has no platform_admin, no enabled tool, and no enabled agent template. There is no default account to log into, no vendor preset to review and strip down, and no starter kit of tools quietly switched on. Every authenticated user can reach the platform, but there is nothing yet for them to use.

This is a deliberate inversion of the usual SaaS posture, where a new tenant ships with a broad default surface and the operator's job is to opt out of what they don't want. Here, the operator opts in, one capability at a time — the natural fit for an on-premise, air-gapped, or classified deployment where "what could this platform possibly do" needs to have a short, exact answer.

The one-shot bootstrap

The first platform_admin is created by a single self-promotion call, gated on two independent proofs — a real authenticated identity (a valid login) and a deploy-time secret that Fred never generates or logs itself. In production that secret comes from the deployment's normal Kubernetes secrets pipeline; for local development it's a file created on demand. Neither proof alone is enough.

POST /bootstrap/platform-admin
{ "token": "<deploy-time secret>" }

→ grants platform_admin to the caller's own identity — never a third party

The call always targets the caller's own identity — there's no field to name someone else, so it can't be used to plant an admin account for a person who isn't the one holding the secret and doing the bootstrapping. And it's genuinely one-shot: once any platform admin has ever been bootstrapped this way, the endpoint refuses permanently. There's no standing default-admin account left behind to rotate or forget about, and no route back in once it's done except through a separate, deliberate recovery procedure.

The resulting platform_admin carries no team relation of any kind — being able to bootstrap the platform doesn't grant access to any team's data, conversations, or content. That access, if any, is a separate and explicit decision (see below).

Source: fred docs docs/swift/platform/REBAC.md — "Team bootstrap" · control-plane bootstrap/api.py

Turning on what's allowed

Once bootstrapped, the platform admin decides what this deployment is allowed to run. "Capability" covers two kinds of thing through the exact same mechanism: an individual tool (an MCP-style integration) and a whole agent template. Enabling a template doesn't side-step the tool-level decision — a template is admitted through the identical admin-only enable/disable action as a single tool, not a separate, looser path.

Enablement has a scope, most-specific wins:

This deployment's policy is to reject the platform-wide-default option. The MCP tool catalog — every third-party and internal tool a deployment can wire in — is guarded by a scan test: no server may declare team_scope: default_on without a security-reviewed waiver, and today that waiver list is empty. So for the tool catalog, the "no default-on surface" claim is a checked invariant, not just a convention.
One built-in capability is a deliberate exception to that policy: document_access (the baseline RAG/document-search capability shipped in fred_runtime, not the MCP catalog) declares team_scope=TeamScopePolicy.DEFAULT_ON in its own manifest — "baseline document access should work without a per-team admin gate." With the control-plane's default capabilities.default_policy: "seed", that seed is honored automatically: the first time document_access registers, it is granted platform-wide to every team, no admin action required. An admin can flip default_policy to "explicit" deployment-wide to suppress all such seeds, or revoke the grant afterwards — but out of the box, this one capability is on by default. The scan test above only reads the static MCP catalog YAML; it does not — and by design cannot — see in-code fred_runtime manifests like this one, so document_access is not something that guard catches or prevents.

Team admins and editors have no say in any of this — enabling a capability for their team (or overriding document_access's default grant) is exclusively a platform-admin action. What a team's own roles control is what that team does with what's already been granted to it: configuring it, using it, building agent instances from an enabled template.

Source: fred docs docs/swift/rfc/AGENT-CAPABILITY-RFC.md §8 · control-plane capabilities/api.py, config/models.py (CapabilitiesConfig.default_policy), capabilities/seeding.py · runtime fred_runtime/capabilities/document_access/capability.py · guard test apps/fred-agents/tests/test_capability_team_scope_policy.py

Teams are created admin-first

Team creation is a separate one-shot, platform-admin-gated action: it names the team's first admin(s) in the same call that creates it.

POST /teams
{ "name": "finance", "initial_team_admin_ids": ["alice"] }

→ creates the team and its first team_admin(s) — nothing else

There is no path to a team that exists with zero admins, and no post-install script left to guess at ownership. The platform admin who creates a team gets no access to it themselves unless they explicitly name their own account in that same call — an explicit, visible, revocable choice, never an implicit side effect of being able to create teams at all.

Users see only what their team was granted

From here it's ordinary team-role administration: a team admin brings in members and assigns them roles, and each member's chat experience is scoped to the subset of platform-enabled capabilities their team was actually granted. A capability the platform admin never enabled doesn't exist for anyone. A capability enabled platform-wide but never granted to a specific team doesn't appear for that team either. The full relation model behind this — how a person's team roles resolve into what they can read, update, or run — is covered in Access model.

Why this is the sovereignty story

Every enabled capability in a Fred deployment traces back to one auditable decision, made by whoever held the bootstrap secret at install time and every platform admin they've since trusted. Nothing is enabled because a vendor shipped it that way. Nothing is enabled because a default was never reviewed. For an on-premise, air-gapped, or otherwise sovereignty-sensitive deployment, that turns "what can this platform possibly do" from a question you answer by auditing a vendor's defaults into a question you answer by reading your own admin's grant history — and it means revoking a capability is the same one auditable action as granting it.