Federation, Bureau, and City
Separate global services, product identity, product backends, and Agent terminals.
In @downcity/city the server and the client are two different classes with two different names. The most common mistake is treating both of them as "City".
- global services and the trust root are the
Federation - stable product identity and authorization domain are the
Bureau - the Agent terminal client is
City
This page solves one thing: so that when you read code, you immediately know which side you are writing.
One-line distinction
Federation: shared runtime, account source of truth, and trust root. It owns the Bureau registry and Organization relationships.Bureau: stable product identity and authorization domain. Every machine credential is bound to onebureau_id.City: an Agent terminal client connected to a configured Bureau domain. It is not registered in Federation.FederationAdmin: the legacy administrator client authorized by an Admin Session; it belongs to no Bureau.
In short: Federation trusts Bureaus; City is only a terminal connected to one Bureau product domain.
Server side: Federation
The server always starts from new Federation({ database }). It assembles the database, services, model catalog, and unified routing into a runnable backend:
import { Federation, Service } from "@downcity/federation";
const base = new Federation({ database });
base.use(new Service({ id: "translate" }));
await base.health();
serve({ fetch: (request) => base.fetch(request), port: 3001 });Federation owns:
- registering
Service, official services, andAIService - verifying
user_tokenand administrator session tokens - exposing the unified
/v1/*routes - coordinating runtime env, hooks, usage, and the database
Control plane and terminal
Trusted control planes and Agent terminals use separate clients:
import { City, FederationAdmin } from "@downcity/federation/legacy";
// Legacy administrator client: requests Bureau, env, and User Token operations from Federation
const admin = new FederationAdmin({
base_url: "https://base.example.com",
credential: administrator_session_token,
});
// Product frontend: only holds user_token (which contains bureau_id), calls services
const city = new City({
federation_url: "https://base.example.com",
user_token,
});FederationAdmin: runs in a trusted backend; requests Federation to manage Bureau identities and env, and to issueuser_token.City: runs in an Agent terminal, holdsuser_token(which containsbureau_id), and calls AI and Service actions.
The client never receives provider keys, and User City never receives administrator credentials or session tokens.
One diagram for the boundary
new City({ federation_url })new Federation({ database })How the CLI maps to this
The CLI is split along the same boundary:
downfed: manages theFederation, Bureau identities, machine credentials, service resources, and env.downcity: the local Agent host and management entry.
What to read next
- For the full request chain, read Architecture
- To separate the two kinds of keys, read Token model
- To deploy hands-on, read Create Federation