Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 10 additions & 14 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,8 @@ HUB_STATIC_DIR=../web/dist

# The administrator account: the hub seeds it at boot and makes it the
# owner of the root tenant (WORKBENCH_DEFAULT_TENANT below), so a fresh
# checkout can sign in immediately and `workbench setup` / `workbench
# seed` authenticate as it. Sign in with these credentials right away.
# Unset values fall back to the defaults shown. The hub itself also
# checkout can sign in immediately. Sign in with these credentials right
# away. Unset values fall back to the defaults shown. The hub itself also
# authenticates as this account (and resolves the same root slug) to
# find the operator bench for the env-key auto-plant — see
# ANTHROPIC_API_KEY further down.
Expand All @@ -61,8 +60,8 @@ HUB_STATIC_DIR=../web/dist
# as configured — it fails loudly at boot instead.

# Slug of the root tenant the hub ensures at boot. Every self-served
# personal bench parents under it, and `workbench setup` / `workbench
# seed` / the env-key auto-plant resolve the same slug. Unset falls back
# personal bench parents under it, and the env-key auto-plant resolves
# the same slug. Unset falls back
# to "workbench". ORG_SLUG is an alias when this is unset — set only one.
# Upgrading a deploy whose existing root was not "workbench": set this
# to that slug (do not leave OPERATOR_TENANT_ID; the hub refuses to boot
Expand Down Expand Up @@ -94,15 +93,12 @@ HUB_STATIC_DIR=../web/dist
# may register (comma-separated). Empty/unset = any domain.
# WORKBENCH_ALLOWED_EMAIL_DOMAINS=acme.example

# Your Anthropic API key — set it for real AI replies. The hub now
# plants it as a real, probed credential on the operator bench itself at
# hub start (the env-key auto-plant, CL-6101): no `workbench seed`
# re-run needed to make the catalog launchable. It also still decides
# whether a freshly self-served personal bench gets the default workflow
# set deployed at first login. `workbench seed` still reads it too, for
# CI/scripted use — both paths are idempotent against each other and
# against themselves; running either (or both, or a hub restart) any
# number of times plants the credential once.
# Your Anthropic API key — set it for real AI replies. The hub plants it
# as a real, probed credential on the operator bench at hub start (the
# env-key auto-plant). Boot itself does not deploy workflows. Catalog
# rows may appear from that plant when the key is set. A freshly
# self-served personal bench gets the default workflow set through
# onboarding once someone connects a provider.
# ANTHROPIC_API_KEY=

# Every other curated provider's key, read the same way and auto-planted
Expand Down
15 changes: 8 additions & 7 deletions IMPLEMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,20 @@ recorded per-package in each vendored package's own `VENDORED-FROM` file.
| Command | What it does |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| `bun run dev` | Validates `.env`, verifies the database, applies pending migrations, builds the web UI if needed, starts the hub and one sidecar |
| `bun run setup` | Provisions the bench for the administrator account |
| `bun run seed` | Deploys the default workflow set and plants the tenant catalog's model data |
| `bun run setup` | Applies pending database migrations (`scripts/db-setup.ts`) |
| `bun run reset` | Drops the platform database schema and clears on-disk asset directories (local `DATABASE_URL` only, unrecoverable) |
| `bun run check` | The full gate: `typecheck && lint && test` — must pass before every commit |
| `bun run test` | Workspace unit/integration tests |
| `bun run test:e2e` | End-to-end smoke tests (`scripts/e2e/*.test.ts`) |
| `bun run format` | `prettier --write .` |

`bun run dev` seeds only the administrator account; `setup` and `seed` are
run separately against the running stack and are safe to re-run.
`ANTHROPIC_API_KEY` is the one optional variable worth setting before
`bun run seed` — without it, everything still runs, but inference errors
until a key is set and seeding is re-run.
`bun run dev` seeds the administrator account and ensures the root
tenant; it does not insert agents, tools, workflows, or skills. An empty
database is a valid hub. `bun run setup` applies migrations against the
running database and is safe to re-run. `ANTHROPIC_API_KEY` is the one
optional variable worth setting before boot — the env-key auto-plant
puts a real credential on the operator bench when it is set; without it,
inference waits until someone connects a provider.

## Acceptance mechanism: the e2e browser walkthrough

Expand Down
34 changes: 16 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,14 @@ Every required setting lives in `.env.example` with its expected shape, and the
defaulting to alice@example.com / password123 when unset)
is seeded so you can sign in immediately.

`bun run dev` seeds that account and, once the hub is serving, also
provisions and seeds the root tenant itself: publishing the
`corbits-tools` registry, deploying the default workflow set, and
planting the tenant catalog's model data, so interactive instances have
a model to resolve against. This runs automatically on every hub boot
(`apps/hub/src/system-seed.ts`), reads its configuration from `.env`
(see `.env.example`), and is safe to re-run — restarting the hub
re-seeds idempotently. `ANTHROPIC_API_KEY` is the one optional line
worth setting before boot — with it, seeding plants a real credential
and the catalog is actually launchable; without it, everything above
still runs, but inference errors until you set it and restart the hub.
`bun run dev` seeds that administrator account and ensures the root
tenant so you can sign in. An empty database is a valid hub: boot does
not insert agents, tools, workflows, or skills. Product state arrives
through onboarding and explicit seed callers, not production boot.
`ANTHROPIC_API_KEY` is the one optional line worth setting before boot —
with it, the env-key auto-plant puts a real credential on the operator
bench so the catalog is launchable; without it, inference waits until
someone connects a provider.

Leaving `ANTHROPIC_API_KEY` unset doesn't just apply to the administrator
account: anyone who signs up gets a personal bench with no default routines
Expand All @@ -98,7 +95,8 @@ it's actually dialed for real inference, through the same in-chat "Fix this
connection" flow any credential failure uses. The bench's default agents
deploy in the background — "Your workbench is ready — agents will come
online shortly," no "Connecting…" wait in the browser. Whichever provider they connect gets its own curated
catalog entry planted the same way boot-time seeding plants Anthropic's; see
catalog entry planted the same way onboarding plants a connected
provider's catalog; see
[docs/model-seeding.md](docs/model-seeding.md) for how that catalog data is
curated and kept up to date.

Expand All @@ -112,12 +110,12 @@ bun run reset
```

`bun run reset` drops the platform database schema and removes the hub's
on-disk asset directory (which also holds provisioned sidecar state)
everything boot-time
seeding and onboarding created. Nothing is re-seeded until the next `bun
run dev` — that recreates the schema and, once the hub is serving again,
reprovisions and re-seeds the root tenant from scratch, landing you at a
fresh sign-up screen with the administrator's bench ready.
on-disk asset directory (which also holds provisioned sidecar state).
Nothing is recreated until the next `bun run dev` — that recreates the
schema and, once the hub is serving again, ensures the administrator
account and root tenant so you can sign in. It does not insert agents,
tools, workflows, or skills. Product state arrives through onboarding
and explicit seed callers.

It refuses to run against anything but a local `DATABASE_URL` (localhost,
127.0.0.1, or `::1`) — there is no override, since the schema drop is
Expand Down
31 changes: 0 additions & 31 deletions apps/hub/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,28 +273,10 @@ function parsePositiveMsEnv(
return n;
}

const SEED_MODEL_PROVIDER = "anthropic";
const SEED_MODEL = "claude-sonnet-5";

// Matches boot-time seeding's own defaults (`system-seed.ts`) exactly,
// so a zero-.env-edit local checkout that seeds its admin account
// through `bun run dev` also resolves the same operator bench for the
// env-key auto-plant with no extra configuration.
const DEFAULT_PLANT_ADMIN_EMAIL = "alice@example.com";
const DEFAULT_PLANT_ADMIN_PASSWORD = "password123";
const DEFAULT_PLANT_ORG_SLUG = "workbench";

/** The root tenant's boot-time seed model: a provider/model pair
* `seedTenant` names in every deployed definition, plus the real (or
* placeholder) key `seedCatalog` plants a launchable credential with. No
* `baseURL` — a workflow deploy resolves inference from the tenant's
* catalog offerings, never a bare source tuple (CL-7461). */
export type ModelSource = {
readonly provider: string;
readonly model: string;
readonly apiKey: string;
};

// One member per implemented `SidecarProvisioner` backend. Adding a new
// backend (e.g. a remote sandbox) is: implement the contract in its own
// package, add a member here with its settings, add its id to
Expand Down Expand Up @@ -365,7 +347,6 @@ export type HubConfig = {
readonly signupMode: "open" | "closed";
/** Domains allowed when signupMode is open. Empty = any domain. */
readonly allowedEmailDomains: readonly string[];
readonly seedModel?: ModelSource;
readonly socialProviders: Readonly<
Partial<Record<SocialProviderId, SocialProviderCredential>>
>;
Expand Down Expand Up @@ -630,16 +611,6 @@ function sidecarProvisionerConfigFor(
}
}

function seedModelFrom(parsed: ParsedHubEnv): ModelSource | undefined {
const apiKey = parsed.ANTHROPIC_API_KEY;
if (apiKey === undefined) return undefined;
return {
provider: SEED_MODEL_PROVIDER,
model: SEED_MODEL,
apiKey,
};
}

/**
* Parse the hub's configuration out of an environment map. Throws at
* the call site when any variable is missing or malformed, reporting
Expand Down Expand Up @@ -668,7 +639,6 @@ export function readHubConfig(
);
}

const seedModel = seedModelFrom(parsed);
const socialProviders = socialProvidersFrom(parsed);
const sidecarProvisioners = sidecarProvisionersFrom(parsed);

Expand Down Expand Up @@ -737,7 +707,6 @@ export function readHubConfig(
hubConfig.routineSchedulerPollIntervalMs = Number(
parsed.ROUTINE_SCHEDULER_POLL_INTERVAL_MS,
);
if (seedModel !== undefined) hubConfig.seedModel = seedModel;
if (parsed.HUGGINGFACE_OAUTH_CLIENT_ID !== undefined)
hubConfig.huggingfaceOAuthClientId = parsed.HUGGINGFACE_OAUTH_CLIENT_ID;
if (parsed.GITHUB_APP_CLIENT_ID !== undefined)
Expand Down
18 changes: 2 additions & 16 deletions apps/hub/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ import { generateId } from "@intx/hub-common";

import { ensureDefaultTenant } from "./default-tenant";
import { createHubSignupTenancy } from "./signup-tenancy";
import { runSystemSeed } from "./system-seed";
import {
createInMemoryMailboxEventBus,
createMailboxDb,
Expand Down Expand Up @@ -405,9 +404,8 @@ const MAX_TARBALL_BYTES = 10 * 1024 * 1024;
// `@corbits` scope at this registry name means a `@corbits/*` pin
// resolves only once an operator publishes a `package-registry` asset
// named `CORBITS_TOOLS_REGISTRY` with the package's tarball —
// `workbench setup` does exactly that onto the root tenant via
// `@corbits/tool-registry-publish`; descendants inherit it, and
// `seedTenant` does not pack. Until then, resolution fails loud
// `@corbits/tool-registry-publish` is the publisher. Descendants
// inherit it, and `seedTenant` does not pack. Until then, resolution fails loud
// rather than silently falling through to npmjs (which could never
// carry an unpublished scope anyway).
const TENANT_PREFIX = "/api/tenants/:tenantId";
Expand Down Expand Up @@ -3691,18 +3689,6 @@ if (import.meta.main) {
});
const log = getLogger(["hub"]);
log.info`Hub serving on port ${port}`;
// CL-7382: replaces `workbench seed`. Runs against the hub's own real
// origin now that it is actually listening — `runSystemSeed`'s
// workflow push needs a reachable origin for `git push`, not just an
// in-process fetch entry point. Never awaited: a slow or still-
// sidecar-less seed must not delay "Hub serving" or hold up shutdown
// wiring below it.
void runSystemSeed({
baseUrl: config.baseUrl,
orgSlug: config.defaultTenantSlug,
admin: config.envCredentialPlantAdmin,
...(config.seedModel !== undefined ? { seedModel: config.seedModel } : {}),
});
const SHUTDOWN_DRAIN_MS = 10_000;
// In-flight Hono handlers (a request mid-Postgres-transaction, a git
// write, anything that has not returned a Response yet) must finish
Expand Down
Loading
Loading