From 096f8450ee76a2226a3d5aba3623b0995bbab091 Mon Sep 17 00:00:00 2001 From: ishaan1124 Date: Sun, 5 Jul 2026 22:53:27 +0530 Subject: [PATCH 1/8] refactor(cli): promote Atlas verbs to top-level commands openscience login/logout/status/sync/devices are now first-class commands; connect stays as a back-compat umbrella alias. Extract runAtlasLogin() so the setup wizard can reuse it, and have status report wallet balance and routing. --- backend/cli/src/cli/cmd/connect.ts | 166 +++++++++++++++-------------- 1 file changed, 87 insertions(+), 79 deletions(-) diff --git a/backend/cli/src/cli/cmd/connect.ts b/backend/cli/src/cli/cmd/connect.ts index f4ae7ff..bf3e775 100644 --- a/backend/cli/src/cli/cmd/connect.ts +++ b/backend/cli/src/cli/cmd/connect.ts @@ -4,69 +4,6 @@ import { UI } from "../ui" import { OpenScience, API_BASE } from "../../openscience" import { openUrl } from "../../util/open-url" -export const ConnectCommand = cmd({ - command: "connect", - describe: "connect to the Synthetic Sciences dashboard", - builder: (yargs) => - yargs - .command(ConnectLoginCommand) - .command(ConnectLogoutCommand) - .command(ConnectStatusCommand) - .command(ConnectSyncCommand) - .command(ConnectDevicesCommand) - .demandCommand(), - async handler() {}, -}) - -const ConnectLoginCommand = cmd({ - command: "login", - describe: "authenticate CLI with the dashboard", - builder: (yargs) => - yargs - .option("key", { - type: "string", - describe: "paste a thk_ API key directly (for headless / CI machines)", - }) - .option("browser", { - type: "boolean", - default: true, - describe: "open a browser to log in; pass --no-browser on headless machines", - }), - async handler(args) { - UI.empty() - prompts.intro("OpenScience") - - const existing = await OpenScience.getSession() - if (existing) { - // Name the backend: "authenticated" only means a key is saved locally. - // If requests then fail, the user can see WHICH host they point at. - prompts.log.success(`Already authenticated (backend: ${API_BASE})`) - await syncAndReport() - prompts.outro("Done") - return - } - - // Non-interactive / CI: a key from --key or env short-circuits the - // whole interactive flow. - const provided = (args.key as string | undefined) || process.env.SYNSC_CLI_KEY || process.env.SYNSC_API_KEY - if (provided) { - if (await finishWithKey(provided)) prompts.outro("Done") - return - } - - // Interactive with a usable browser → loopback login (zero typing). - if (args.browser !== false && !isHeadless()) { - if (await tryBrowserLogin()) { - prompts.outro("Done") - return - } - // Browser flow failed/timed out — fall through to manual paste. - } - - if (await manualKeyLogin()) prompts.outro("Done") - }, -}) - /** Best-effort detection of environments where opening a browser and * binding a loopback callback won't work (CI, SSH without a display, * non-TTY pipelines). When true we skip straight to the paste flow. */ @@ -88,7 +25,7 @@ async function syncAndReport() { // the backend rejected the key. Never leave "authenticated" looking healthy // while every request silently fails — say what happened and against which host. if (!(await OpenScience.getSession())) { - prompts.log.warn(`${API_BASE} rejected your saved key. Run \`openscience connect login\` to re-authenticate.`) + prompts.log.warn(`${API_BASE} rejected your saved key. Run \`openscience login\` to re-authenticate.`) return } prompts.log.warn( @@ -157,16 +94,65 @@ async function manualKeyLogin(): Promise { return await finishWithKey(pasted) } -const ConnectLogoutCommand = cmd({ +/** Core Atlas sign-in, shared by `openscience login` and the setup wizard. + * Returns true if the CLI is authenticated when it finishes. Carries no + * intro/outro framing so callers own the surrounding UI. */ +export async function runAtlasLogin(args: { key?: string; browser?: boolean } = {}): Promise { + const existing = await OpenScience.getSession() + if (existing) { + // "authenticated" only means a key is saved locally. Name the backend so + // that, if requests then fail, the user can see WHICH host they point at. + prompts.log.success(`Already authenticated (backend: ${API_BASE})`) + await syncAndReport() + return true + } + + // Non-interactive / CI: a key from --key or env short-circuits the flow. + const provided = args.key || process.env.SYNSC_CLI_KEY || process.env.SYNSC_API_KEY + if (provided) return await finishWithKey(provided) + + // Interactive with a usable browser → loopback login (zero typing). + if (args.browser !== false && !isHeadless()) { + if (await tryBrowserLogin()) return true + // Browser flow failed/timed out — fall through to manual paste. + } + + return await manualKeyLogin() +} + +export const LoginCommand = cmd({ + command: "login", + describe: "log in to your Atlas account (managed models, wallet, sync)", + builder: (yargs) => + yargs + .option("key", { + type: "string", + describe: "paste a thk_ API key directly (for headless / CI machines)", + }) + .option("browser", { + type: "boolean", + default: true, + describe: "open a browser to log in; pass --no-browser on headless machines", + }), + async handler(args) { + UI.empty() + prompts.intro("OpenScience") + const ok = await runAtlasLogin({ key: args.key as string | undefined, browser: args.browser as boolean }) + prompts.outro(ok ? "Done" : "Not signed in") + }, +}) + +export const LogoutCommand = cmd({ command: "logout", - describe: "disconnect from the dashboard", + describe: "log out of your Atlas account", async handler() { UI.empty() prompts.intro("OpenScience") const session = await OpenScience.getSession() if (!session) { - prompts.log.warn("Not connected") + prompts.log.warn("Not signed in to Atlas.") + prompts.log.info("To remove a saved provider key instead, use `openscience keys rm`.") prompts.outro("Done") return } @@ -175,7 +161,7 @@ const ConnectLogoutCommand = cmd({ // the call, then clear every local credential artifact. const revoked = await OpenScience.revokeCurrentDevice() await OpenScience.clearSession() - prompts.log.success("Disconnected") + prompts.log.success("Signed out of Atlas") if (!revoked) { prompts.log.info( "Could not revoke this device's key server-side — remove it from the Devices tab at app.syntheticsciences.ai if needed", @@ -185,17 +171,17 @@ const ConnectLogoutCommand = cmd({ }, }) -const ConnectStatusCommand = cmd({ - command: "status", - describe: "show connection status", +export const StatusCommand = cmd({ + command: ["status", "whoami"], + describe: "show Atlas connection, account, and wallet", async handler() { UI.empty() prompts.intro("OpenScience") const session = await OpenScience.getSession() if (!session) { - prompts.log.warn("Not connected") - prompts.log.info("Run `openscience connect login` to authenticate") + prompts.log.warn("Not connected to Atlas") + prompts.log.info("Run `openscience login` to connect, or `openscience keys add` to use your own key.") prompts.outro("Done") return } @@ -214,20 +200,26 @@ const ConnectStatusCommand = cmd({ prompts.log.info(`Subscription: ${result.user.subscription_status}`) } } else if (!(await OpenScience.getSession())) { - prompts.log.warn(`${API_BASE} rejected your saved key. Run \`openscience connect login\` to re-authenticate.`) + prompts.log.warn(`${API_BASE} rejected your saved key. Run \`openscience login\` to re-authenticate.`) } else { prompts.log.warn( `Could not reach ${API_BASE} to verify services — the saved session is untested against the backend.`, ) } + const mode = await OpenScience.getBillingMode().catch(() => null) + if (mode) { + prompts.log.info(`Wallet: $${mode.balance_usd.toFixed(2)}`) + prompts.log.info("Routing: per-provider (auto) — your key if set, else Atlas managed (debits wallet).") + } + prompts.outro("Done") }, }) -const ConnectSyncCommand = cmd({ +export const SyncCommand = cmd({ command: "sync", - describe: "sync service credentials from the dashboard", + describe: "sync service credentials from your Atlas account", async handler() { UI.empty() prompts.intro("OpenScience") @@ -235,7 +227,7 @@ const ConnectSyncCommand = cmd({ const session = await OpenScience.getSession() if (!session) { prompts.log.warn("Not connected") - prompts.log.info("Run `openscience connect login` to authenticate") + prompts.log.info("Run `openscience login` to authenticate") prompts.outro("Done") return } @@ -255,7 +247,7 @@ const ConnectSyncCommand = cmd({ }, }) -const ConnectDevicesCommand = cmd({ +export const DevicesCommand = cmd({ command: "devices", describe: "list authenticated devices", async handler() { @@ -265,7 +257,7 @@ const ConnectDevicesCommand = cmd({ const session = await OpenScience.getSession() if (!session) { prompts.log.warn("Not connected") - prompts.log.info("Run `openscience connect login` to authenticate") + prompts.log.info("Run `openscience login` to authenticate") prompts.outro("Done") return } @@ -289,3 +281,19 @@ const ConnectDevicesCommand = cmd({ prompts.outro("Done") }, }) + +/** Back-compat umbrella: `openscience connect ` + * still works and forwards to the promoted top-level commands. */ +export const ConnectCommand = cmd({ + command: "connect", + describe: "Atlas account (alias for `login` / `logout` / `status` / `sync` / `devices`)", + builder: (yargs) => + yargs + .command(LoginCommand) + .command(LogoutCommand) + .command(StatusCommand) + .command(SyncCommand) + .command(DevicesCommand) + .demandCommand(), + async handler() {}, +}) From ed10cba3d0d12b1cce4b7ea0ae3ab786e5587e5f Mon Sep 17 00:00:00 2001 From: ishaan1124 Date: Sun, 5 Jul 2026 22:53:27 +0530 Subject: [PATCH 2/8] feat(cli): add first-run setup wizard, openscience init, and doctor Managed-first fork (Atlas managed / your own keys / not now) that never blocks BYOK or account-free use, offers the Atlas CLI companion, and writes a marker so it only auto-runs once. init reruns it; doctor reports what is configured. --- backend/cli/src/cli/onboard.ts | 239 +++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 backend/cli/src/cli/onboard.ts diff --git a/backend/cli/src/cli/onboard.ts b/backend/cli/src/cli/onboard.ts new file mode 100644 index 0000000..dbdc663 --- /dev/null +++ b/backend/cli/src/cli/onboard.ts @@ -0,0 +1,239 @@ +import * as prompts from "@clack/prompts" +import path from "path" +import { cmd } from "./cmd/cmd" +import { UI } from "./ui" +import { OpenScience } from "../openscience" +import { Auth } from "../auth" +import { Config } from "../config/config" +import { Global } from "../global" +import { openUrl } from "../util/open-url" +import { runAtlasLogin } from "./cmd/connect" +import { AuthLoginCommand } from "./cmd/auth" + +const PLAN_URL = process.env.SYNSC_AUTH_URL?.replace(/\/+$/, "") || "https://app.syntheticsciences.ai/cli" +const MARKER = path.join(Global.Path.state, "onboarded") + +/** Provider env vars that count as "already configured" so we never nag a + * user who exported a key in their shell. Deliberately not exhaustive — a + * false negative just re-offers setup, which is harmless. */ +const PROVIDER_ENV_KEYS = [ + "ANTHROPIC_API_KEY", + "OPENAI_API_KEY", + "GEMINI_API_KEY", + "GOOGLE_GENERATIVE_AI_API_KEY", + "OPENROUTER_API_KEY", + "GROQ_API_KEY", + "MISTRAL_API_KEY", + "XAI_API_KEY", + "DEEPSEEK_API_KEY", + "CEREBRAS_API_KEY", + "TOGETHER_API_KEY", + "PERPLEXITY_API_KEY", +] + +function hasProviderEnv(): boolean { + return PROVIDER_ENV_KEYS.some((k) => !!process.env[k]) +} + +/** True once the user has any usable way to run a model: a managed Atlas + * session, a saved BYOK key, a provider env var, or an explicit default + * model in config. Used to decide whether to auto-launch onboarding and + * whether to warn about a missing model. */ +export async function isConfigured(): Promise { + if (await OpenScience.isAuthenticated()) return true + if (hasProviderEnv()) return true + try { + if (Object.keys(await Auth.all()).length > 0) return true + } catch {} + try { + const config = await Config.get() + if (config.model) return true + } catch {} + return false +} + +async function isOnboarded(): Promise { + try { + return await Bun.file(MARKER).exists() + } catch { + return false + } +} + +async function markOnboarded(): Promise { + try { + await Bun.write(MARKER, new Date().toISOString() + "\n") + } catch {} +} + +/** Whether to auto-launch the first-run wizard from the default command. + * Gated on an interactive TTY plus "nothing configured yet"; suppressed in + * CI, when piped, once the marker is set, or via OPENSCIENCE_NO_ONBOARD=1. */ +export async function needsOnboarding(): Promise { + if (process.env.OPENSCIENCE_NO_ONBOARD === "1") return false + if (process.env.CI) return false + if (!process.stdin.isTTY || !process.stdout.isTTY) return false + if (await isOnboarded()) return false + if (await isConfigured()) return false + return true +} + +async function onboardManaged(): Promise { + const existing = await OpenScience.getSession() + if (existing) { + prompts.log.success("Already connected to your Atlas account.") + await OpenScience.syncServices().catch(() => {}) + } else { + const ok = await runAtlasLogin({}) + if (!ok) { + prompts.log.warn("Skipped Atlas sign-in. Run `openscience login` anytime to connect.") + return + } + } + + const mode = await OpenScience.getBillingMode().catch(() => null) + const balance = mode?.balance_usd ?? (await OpenScience.getBalance().catch(() => null)) ?? 0 + prompts.log.info(`Atlas wallet: $${balance.toFixed(2)}`) + + if (balance <= 0) { + const add = await prompts.confirm({ + message: "Add funds now so you can use managed models?", + initialValue: true, + }) + if (!prompts.isCancel(add) && add) { + prompts.log.info(`Opening ${PLAN_URL} …`) + prompts.log.message("Top up in the Plan tab, then come back here — your balance updates automatically.") + openUrl(PLAN_URL) + } else { + prompts.log.info(`No problem — top up anytime with \`openscience wallet\` or at ${PLAN_URL}.`) + } + } + prompts.log.info( + "Managed models are metered from your wallet. Switch to your own keys anytime with `openscience keys add`.", + ) +} + +async function onboardByok(): Promise { + prompts.log.info("Bring your own key — pick a provider next. Keys stay on this machine and are always free.") + // Reuse the proven provider picker + key/OAuth flow. It also handles + // Claude Max / ChatGPT / Copilot sign-in via the provider auth plugins. + await AuthLoginCommand.handler({} as never) +} + +function onboardSkip(): void { + prompts.log.info("No problem — start right away with the free demo models.") + prompts.log.message( + "When you're ready:\n" + + " openscience login connect Atlas managed models (prepaid wallet)\n" + + " openscience keys add add your own provider key (always free)", + ) +} + +async function offerAtlasCli(): Promise { + if (Bun.which("atlas")) return + const yes = await prompts.confirm({ + message: "Install the Atlas CLI companion? (research graph — maps, runs, library)", + initialValue: false, + }) + if (prompts.isCancel(yes) || !yes) return + + if (!Bun.which("npm")) { + prompts.log.info("Install it later with: npm i -g @synsci/atlas@latest") + return + } + const spin = prompts.spinner() + spin.start("Installing @synsci/atlas…") + try { + const proc = Bun.spawn(["npm", "install", "-g", "@synsci/atlas@latest"], { stdout: "ignore", stderr: "pipe" }) + const code = await proc.exited + if (code === 0) { + spin.stop("Atlas CLI installed — it shares your session, so it's already signed in.") + } else { + spin.stop("Couldn't install automatically. Run: npm i -g @synsci/atlas@latest", 1) + } + } catch { + spin.stop("Couldn't install automatically. Run: npm i -g @synsci/atlas@latest", 1) + } +} + +/** The first-run setup wizard. Managed-first, but bring-your-own-key and + * "not now" stay one keystroke away — OpenScience never requires an account. */ +export async function runOnboarding(opts?: { force?: boolean }): Promise { + prompts.intro(opts?.force ? "OpenScience setup" : "Welcome to OpenScience") + + const choice = await prompts.select({ + message: "How do you want to power the models?", + initialValue: "managed", + options: [ + { value: "managed", label: "Atlas managed", hint: "★ recommended · prepaid wallet · zero setup" }, + { value: "byok", label: "Your own keys", hint: "Anthropic · OpenAI · Google · 100+ providers · always free" }, + { value: "skip", label: "Not now", hint: "free demo models now, set up anytime" }, + ], + }) + if (prompts.isCancel(choice)) { + prompts.cancel("Setup cancelled — run `openscience init` whenever you're ready.") + await markOnboarded() + return + } + + if (choice === "managed") await onboardManaged() + else if (choice === "byok") await onboardByok() + else onboardSkip() + + await offerAtlasCli() + await markOnboarded() + prompts.outro("You're all set.") +} + +export const InitCommand = cmd({ + command: ["init", "onboard"], + describe: "set up OpenScience — models, keys, and Atlas", + async handler() { + UI.empty() + UI.println(UI.logo(" ")) + UI.empty() + await runOnboarding({ force: true }) + }, +}) + +export const DoctorCommand = cmd({ + command: "doctor", + describe: "check what's configured and what's missing", + async handler() { + UI.empty() + prompts.intro("openscience doctor") + + const session = await OpenScience.getSession() + if (session) { + prompts.log.success("Atlas account: connected") + const mode = await OpenScience.getBillingMode().catch(() => null) + if (mode) { + const suffix = mode.managed_supported ? "" : " (managed not provisioned)" + prompts.log.info(`Wallet: $${mode.balance_usd.toFixed(2)}${suffix}`) + } + } else { + prompts.log.info("Atlas account: not connected (run `openscience login`)") + } + + try { + const keys = Object.keys(await Auth.all()) + if (keys.length) prompts.log.success(`Provider keys: ${keys.join(", ")}`) + else prompts.log.info("Provider keys: none (run `openscience keys add`)") + } catch {} + + const envKeys = PROVIDER_ENV_KEYS.filter((k) => !!process.env[k]) + if (envKeys.length) prompts.log.info(`Environment keys: ${envKeys.join(", ")}`) + + try { + const config = await Config.get() + prompts.log.info(`Default model: ${config.model ?? "auto (chosen from available providers)"}`) + } catch {} + + if (!(await isConfigured())) { + prompts.log.warn( + "No model source configured — free demo models will be used. Run `openscience init` to set one up.", + ) + } + prompts.outro("Done") + }, +}) From d0d48dbdd83d645d2b3977c7bfe525a15f3c38f4 Mon Sep 17 00:00:00 2001 From: ishaan1124 Date: Sun, 5 Jul 2026 22:53:27 +0530 Subject: [PATCH 3/8] refactor(cli): rename auth->keys and billing->wallet; wire new command tree BYOK key management is now openscience keys add/rm/ls/signin (auth kept as an alias); wallet is openscience wallet (billing kept as an alias). Codex logout folds into keys rm. The default command launches the wizard on first run and no longer nags BYOK users to connect Atlas. --- backend/cli/src/cli/cmd/auth.ts | 59 ++++++++---------------------- backend/cli/src/cli/cmd/billing.ts | 8 ++-- backend/cli/src/cli/cmd/web.ts | 25 +++++++++++-- backend/cli/src/index.ts | 28 ++++++++++---- 4 files changed, 62 insertions(+), 58 deletions(-) diff --git a/backend/cli/src/cli/cmd/auth.ts b/backend/cli/src/cli/cmd/auth.ts index e7f3355..5b28d16 100644 --- a/backend/cli/src/cli/cmd/auth.ts +++ b/backend/cli/src/cli/cmd/auth.ts @@ -174,10 +174,10 @@ async function handlePluginAuth( return false } -export const AuthCommand = cmd({ - command: "login", +export const KeysCommand = cmd({ + command: "keys", aliases: ["auth"], - describe: "manage credentials", + describe: "manage your own provider API keys (BYOK)", builder: (yargs) => yargs .command(AuthLoginCommand) @@ -236,8 +236,8 @@ export const AuthListCommand = cmd({ }) export const AuthLoginCommand = cmd({ - command: "login [url]", - describe: "log in to a provider", + command: ["add [url]", "login [url]"], + describe: "add a provider API key (BYOK)", builder: (yargs) => yargs.positional("url", { describe: "openscience auth provider", @@ -421,8 +421,8 @@ async function backendHasCodex(): Promise { } export const AuthCodexCommand = cmd({ - command: "codex", - describe: "log in to Codex (Sign in with ChatGPT Plus/Pro/Business)", + command: ["signin", "codex"], + describe: "sign in with ChatGPT / Codex (Plus/Pro/Business subscription)", async handler() { await Instance.provide({ directory: process.cwd(), @@ -474,8 +474,8 @@ export const AuthCodexCommand = cmd({ }) export const AuthLogoutCommand = cmd({ - command: "logout", - describe: "log out from a configured provider", + command: ["remove", "rm", "logout"], + describe: "remove a saved provider key", async handler() { UI.empty() const credentials = await Auth.all().then((x) => Object.entries(x)) @@ -494,6 +494,13 @@ export const AuthLogoutCommand = cmd({ }) if (prompts.isCancel(providerID)) throw new UI.CancelledError() await Auth.remove(providerID) + // Removing Codex must also revoke it on the Atlas backend and re-sync so + // the provider list drops openai-codex/* immediately — otherwise the CLI + // and backend drift (local removed, backend still connected). + if (providerID === "openai-codex") { + await revokeCodexOnBackend() + await OpenScience.syncServices?.().catch(() => {}) + } prompts.outro("Logout successful") }, }) @@ -518,37 +525,3 @@ async function revokeCodexOnBackend(): Promise { log.warn("backend codex revoke errored", { error: String(e) }) } } - -export const LogoutCodexCommand = cmd({ - command: "codex", - describe: "log out of Codex (clears local OAuth + revokes on Atlas backend)", - async handler() { - UI.empty() - prompts.intro("Codex logout") - const existing = await Auth.get("openai-codex") - if (!existing) { - prompts.log.info("Not signed in to Codex.") - prompts.outro("Done") - return - } - await Auth.remove("openai-codex") - await revokeCodexOnBackend() - // Re-sync so the local provider list drops openai-codex/* immediately. - await OpenScience.syncServices?.().catch((e: unknown) => { - log.warn("post-logout sync failed", { error: String(e) }) - }) - prompts.outro("Logout successful") - }, -}) - -export const LogoutCommand = cmd({ - command: "logout", - describe: "log out of a connected provider (use `logout codex` for Codex)", - builder: (yargs) => yargs.command(LogoutCodexCommand), - // Default (no subcommand) falls through to the same interactive flow as - // `openscience login logout`. Keeps the existing UX for users who don't know - // the provider id. - async handler() { - await AuthLogoutCommand.handler({} as never) - }, -}) diff --git a/backend/cli/src/cli/cmd/billing.ts b/backend/cli/src/cli/cmd/billing.ts index 1fbcf1a..e281520 100644 --- a/backend/cli/src/cli/cmd/billing.ts +++ b/backend/cli/src/cli/cmd/billing.ts @@ -5,9 +5,9 @@ import { OpenScience } from "../../openscience" const PLAN_URL = process.env.SYNSC_AUTH_URL?.replace(/\/+$/, "") || "https://app.syntheticsciences.ai/cli" -export const BillingCommand = cmd({ - command: "billing", - describe: "show CLI wallet balance and how key routing works", +export const WalletCommand = cmd({ + command: ["wallet", "billing"], + describe: "Atlas wallet — balance, top up, and key routing", builder: (yargs) => yargs.command(BillingShowCommand).command(BillingTopupCommand).demandCommand(), async handler() {}, }) @@ -21,7 +21,7 @@ const BillingShowCommand = cmd({ const session = await OpenScience.getSession() if (!session) { - prompts.log.warn("Not authenticated. Run `openscience connect login` first.") + prompts.log.warn("Not authenticated. Run `openscience login` first.") prompts.outro("Done") return } diff --git a/backend/cli/src/cli/cmd/web.ts b/backend/cli/src/cli/cmd/web.ts index 92195ce..58c584d 100644 --- a/backend/cli/src/cli/cmd/web.ts +++ b/backend/cli/src/cli/cmd/web.ts @@ -5,6 +5,7 @@ import { cmd } from "./cmd" import { withNetworkOptions, resolveNetworkOptions } from "../network" import open from "open" import { openUrl } from "../../util/open-url" +import { needsOnboarding, runOnboarding, isConfigured } from "../onboard" import fs from "fs/promises" import os from "os" import path from "path" @@ -80,6 +81,14 @@ export const WebCommand = cmd({ UI.println(UI.logo(" ")) UI.empty() + // First launch on this machine with nothing configured → walk the user + // through setup (managed vs BYOK vs skip) before we bind the server, so + // the browser's first request already sees a usable model. + if (await needsOnboarding()) { + await runOnboarding() + UI.empty() + } + // Run the dashboard sync BEFORE starting the server — and without // the 5s race timeout the global middleware uses. The model picker // and provider whitelist live in ~/.config/openscience/openscience-synced.json; @@ -90,10 +99,18 @@ export const WebCommand = cmd({ // request sees the freshly-synced whitelist. const authed = await OpenScience.isAuthenticated() if (!authed) { - UI.println(UI.Style.TEXT_WARNING_BOLD + " ⚠ Not connected to Synthetic Sciences", UI.Style.TEXT_NORMAL) - UI.println(UI.Style.TEXT_NORMAL, " Run `openscience connect login` to sync provider keys + managed config.") - UI.println(UI.Style.TEXT_DIM, " Continuing with whatever env vars are already in your shell.") - UI.empty() + // Only nudge when there's genuinely no way to run a model. A BYOK key + // (env var or `keys add`) is a first-class, account-free setup — don't + // badger those users to connect Atlas. + if (!(await isConfigured())) { + UI.println(UI.Style.TEXT_WARNING_BOLD + " ⚠ No model configured", UI.Style.TEXT_NORMAL) + UI.println( + UI.Style.TEXT_NORMAL, + " Run `openscience login` for Atlas managed models, or `openscience keys add` for your own key.", + ) + UI.println(UI.Style.TEXT_DIM, " Continuing with free demo models for now.") + UI.empty() + } } else { // Sync managed config before binding so the browser's first request sees // the fresh provider whitelist. But cap the wait: syncServices() has no diff --git a/backend/cli/src/index.ts b/backend/cli/src/index.ts index 845adfb..a1b917f 100644 --- a/backend/cli/src/index.ts +++ b/backend/cli/src/index.ts @@ -32,10 +32,18 @@ import { EOL } from "os" import { WebCommand } from "./cli/cmd/web" import { PrCommand } from "./cli/cmd/pr" import { SessionCommand } from "./cli/cmd/session" -import { ConnectCommand } from "./cli/cmd/connect" +import { + ConnectCommand, + LoginCommand, + LogoutCommand, + StatusCommand, + SyncCommand, + DevicesCommand, +} from "./cli/cmd/connect" import { ProjectCommand } from "./cli/cmd/project" -import { BillingCommand } from "./cli/cmd/billing" -import { AuthCommand, LogoutCommand } from "./cli/cmd/auth" +import { WalletCommand } from "./cli/cmd/billing" +import { KeysCommand } from "./cli/cmd/auth" +import { InitCommand, DoctorCommand } from "./cli/onboard" import { OpenScience } from "./openscience" process.on("unhandledRejection", (e) => { @@ -126,11 +134,17 @@ const cli = yargs(hideBin(process.argv)) .command(GithubCommand) .command(PrCommand) .command(SessionCommand) - .command(ConnectCommand) - .command(ProjectCommand) - .command(BillingCommand) - .command(AuthCommand) + .command(InitCommand) + .command(LoginCommand) .command(LogoutCommand) + .command(StatusCommand) + .command(SyncCommand) + .command(DevicesCommand) + .command(KeysCommand) + .command(WalletCommand) + .command(DoctorCommand) + .command(ProjectCommand) + .command(ConnectCommand) .fail((msg, err) => { if ( msg?.startsWith("Unknown argument") || From c3b487dce8d0f83dc3d8e398a47a4bb41178587e Mon Sep 17 00:00:00 2001 From: ishaan1124 Date: Sun, 5 Jul 2026 22:53:28 +0530 Subject: [PATCH 4/8] refactor(cli): update in-app command hints to the new verbs --- backend/cli/src/acp/agent.ts | 2 +- backend/cli/src/cli/cmd/project.ts | 8 ++++---- backend/cli/src/cli/cmd/skill.ts | 2 +- backend/cli/src/plugin/codex.ts | 4 +--- backend/cli/src/provider/provider.ts | 2 +- backend/cli/src/session/prompt.ts | 2 +- 6 files changed, 9 insertions(+), 11 deletions(-) diff --git a/backend/cli/src/acp/agent.ts b/backend/cli/src/acp/agent.ts index f392580..81ccbde 100644 --- a/backend/cli/src/acp/agent.ts +++ b/backend/cli/src/acp/agent.ts @@ -415,7 +415,7 @@ export namespace ACP { log.info("initialize", { protocolVersion: params.protocolVersion }) const authMethod: AuthMethod = { - description: "Run `openscience connect login` in the terminal", + description: "Run `openscience login` in the terminal", name: "Login with OpenScience", id: "openscience-login", } diff --git a/backend/cli/src/cli/cmd/project.ts b/backend/cli/src/cli/cmd/project.ts index 12dca86..138a398 100644 --- a/backend/cli/src/cli/cmd/project.ts +++ b/backend/cli/src/cli/cmd/project.ts @@ -44,7 +44,7 @@ const ProjectInitCommand = cmd({ return } UI.empty() - prompts.log.error("Not connected to Atlas. Run `openscience connect login` first.") + prompts.log.error("Not connected to Atlas. Run `openscience login` first.") return } const opened = (args.dir as string | undefined) || process.cwd() @@ -81,8 +81,8 @@ function reportInitFailure(failure: InitProjectFailure | undefined) { case "unauthenticated": prompts.log.error( f.status - ? `${f.host} rejected your saved session (HTTP ${f.status})${detail}. Run \`openscience connect login\` to re-authenticate.` - : "Not connected to Atlas. Run `openscience connect login` first.", + ? `${f.host} rejected your saved session (HTTP ${f.status})${detail}. Run \`openscience login\` to re-authenticate.` + : "Not connected to Atlas. Run `openscience login` first.", ) break case "unreachable": @@ -150,7 +150,7 @@ const ProjectMergeCommand = cmd({ const session = await OpenScience.getSession() if (!session) { - prompts.log.error("Not authenticated. Run `openscience connect login` first.") + prompts.log.error("Not authenticated. Run `openscience login` first.") prompts.outro("Aborted") return } diff --git a/backend/cli/src/cli/cmd/skill.ts b/backend/cli/src/cli/cmd/skill.ts index d42ebb7..9aade3c 100644 --- a/backend/cli/src/cli/cmd/skill.ts +++ b/backend/cli/src/cli/cmd/skill.ts @@ -300,7 +300,7 @@ const SkillListCommand = cmd({ if (totalBundled === 0) { UI.println( - "Bundled OpenScience skills did not load. Run `openscience connect login` and `openscience connect sync`, then try again.", + "Bundled OpenScience skills did not load. Run `openscience login` and `openscience sync`, then try again.", ) UI.println("Offline fallback only shows skills already cached on this machine.") UI.println("") diff --git a/backend/cli/src/plugin/codex.ts b/backend/cli/src/plugin/codex.ts index ec374ac..5def0cd 100644 --- a/backend/cli/src/plugin/codex.ts +++ b/backend/cli/src/plugin/codex.ts @@ -453,9 +453,7 @@ export async function CodexAuthPlugin(input: PluginInput): Promise { } if (!tokens) { log.warn("codex token refresh failed", { error: String(e) }) - throw new Error( - "Codex sign-in expired. Reconnect it with `openscience auth login` and choose Codex — Sign in with ChatGPT.", - ) + throw new Error("Codex sign-in expired. Reconnect it with `openscience keys signin`.") } } } diff --git a/backend/cli/src/provider/provider.ts b/backend/cli/src/provider/provider.ts index def2a62..6fb638d 100644 --- a/backend/cli/src/provider/provider.ts +++ b/backend/cli/src/provider/provider.ts @@ -1414,7 +1414,7 @@ export namespace Provider { } export const NO_PROVIDER_HINT = - "No model providers are available. Add an API key for a provider (`openscience auth login`) or connect a managed account (`openscience connect login`), then choose a model." + "No model providers are available. Add your own API key (`openscience keys add`) or connect a managed account (`openscience login`), then choose a model." const priority = ["claude-sonnet-4", "claude-opus-4", "gpt-5", "gemini-3-pro"] export function sort(models: Model[]) { diff --git a/backend/cli/src/session/prompt.ts b/backend/cli/src/session/prompt.ts index 3278506..1420bec 100644 --- a/backend/cli/src/session/prompt.ts +++ b/backend/cli/src/session/prompt.ts @@ -350,7 +350,7 @@ export namespace SessionPrompt { // removed) — surface a session error instead of crashing the loop. if (!model) { const error = new NamedError.Unknown({ - message: `Model ${lastUser.model.providerID}/${lastUser.model.modelID} is not available. Add an API key for a provider (\`openscience auth login\`) or connect a managed account (\`openscience connect login\`), then choose a model.`, + message: `Model ${lastUser.model.providerID}/${lastUser.model.modelID} is not available. Add your own API key (\`openscience keys add\`) or connect a managed account (\`openscience login\`), then choose a model.`, }).toObject() Bus.publish(Session.Event.Error, { sessionID, error }) await Session.updateMessage({ From 33f22cff22448017aaee299fd34ee0f9e0ebe39e Mon Sep 17 00:00:00 2001 From: ishaan1124 Date: Sun, 5 Jul 2026 22:53:28 +0530 Subject: [PATCH 5/8] feat(install): offer the Atlas CLI companion during install TTY-gated prompt that reads /dev/tty (curl|bash makes stdin the script). Skipped in CI, non-interactive shells, when atlas is already installed, or with --no-atlas / OPENSCIENCE_NO_ATLAS. Mirrored byte-for-byte to the served copy that CI checks. --- frontend/landing/public/install | 28 ++++++++++++++++++++++++++++ install | 28 ++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/frontend/landing/public/install b/frontend/landing/public/install index 2bff5b6..2ba3e0d 100755 --- a/frontend/landing/public/install +++ b/frontend/landing/public/install @@ -18,6 +18,7 @@ Options: -v, --version Install a specific version (e.g., 1.0.180) -b, --binary Install from a local binary instead of downloading --no-modify-path Don't modify shell config files (.zshrc, .bashrc, etc.) + --no-atlas Don't offer to install the Atlas CLI companion Examples: curl -fsSL https://openscience.sh/install | bash @@ -28,6 +29,7 @@ EOF requested_version=${VERSION:-} no_modify_path=false +no_atlas=false binary_path="" while [[ $# -gt 0 ]]; do @@ -58,6 +60,10 @@ while [[ $# -gt 0 ]]; do no_modify_path=true shift ;; + --no-atlas) + no_atlas=true + shift + ;; *) echo -e "${ORANGE}Warning: Unknown option '$1'${NC}" >&2 shift @@ -482,6 +488,28 @@ if [[ -n "$shadow" && "$shadow" != "$INSTALL_DIR/openscience" ]]; then print_message info " npm rm -g @synsci/cli" fi +# Offer the Atlas CLI companion (research graph — maps, runs, shared library). +# Piping via curl|bash makes stdin the script itself, so prompt on /dev/tty. +# Skips when non-interactive, in CI, already installed, or opted out. +if [ "$no_atlas" != true ] && [ -z "${OPENSCIENCE_NO_ATLAS:-}" ] && [ -z "${CI:-}" ] \ + && [ -t 1 ] && [ -r /dev/tty ] && ! command -v atlas >/dev/null 2>&1; then + echo -e "" + echo -e "${MUTED}Atlas is Synthetic Sciences' research graph — maps, runs, and a shared library.${NC}" + printf "Install the Atlas CLI companion too? [y/N] " + read -r atlas_reply /dev/null 2>&1; then + echo -e "${MUTED}Installing @synsci/atlas…${NC}" + npm install -g @synsci/atlas@latest \ + || print_message warning "Atlas install failed — run: npm i -g @synsci/atlas@latest" + else + print_message info "npm not found — install Atlas later with: npm i -g @synsci/atlas@latest" + fi + ;; + esac +fi + echo -e "" echo -e "${MUTED} ${NC}OpenScience" echo -e "${MUTED} by Synthetic Sciences${NC}" diff --git a/install b/install index 2bff5b6..2ba3e0d 100755 --- a/install +++ b/install @@ -18,6 +18,7 @@ Options: -v, --version Install a specific version (e.g., 1.0.180) -b, --binary Install from a local binary instead of downloading --no-modify-path Don't modify shell config files (.zshrc, .bashrc, etc.) + --no-atlas Don't offer to install the Atlas CLI companion Examples: curl -fsSL https://openscience.sh/install | bash @@ -28,6 +29,7 @@ EOF requested_version=${VERSION:-} no_modify_path=false +no_atlas=false binary_path="" while [[ $# -gt 0 ]]; do @@ -58,6 +60,10 @@ while [[ $# -gt 0 ]]; do no_modify_path=true shift ;; + --no-atlas) + no_atlas=true + shift + ;; *) echo -e "${ORANGE}Warning: Unknown option '$1'${NC}" >&2 shift @@ -482,6 +488,28 @@ if [[ -n "$shadow" && "$shadow" != "$INSTALL_DIR/openscience" ]]; then print_message info " npm rm -g @synsci/cli" fi +# Offer the Atlas CLI companion (research graph — maps, runs, shared library). +# Piping via curl|bash makes stdin the script itself, so prompt on /dev/tty. +# Skips when non-interactive, in CI, already installed, or opted out. +if [ "$no_atlas" != true ] && [ -z "${OPENSCIENCE_NO_ATLAS:-}" ] && [ -z "${CI:-}" ] \ + && [ -t 1 ] && [ -r /dev/tty ] && ! command -v atlas >/dev/null 2>&1; then + echo -e "" + echo -e "${MUTED}Atlas is Synthetic Sciences' research graph — maps, runs, and a shared library.${NC}" + printf "Install the Atlas CLI companion too? [y/N] " + read -r atlas_reply /dev/null 2>&1; then + echo -e "${MUTED}Installing @synsci/atlas…${NC}" + npm install -g @synsci/atlas@latest \ + || print_message warning "Atlas install failed — run: npm i -g @synsci/atlas@latest" + else + print_message info "npm not found — install Atlas later with: npm i -g @synsci/atlas@latest" + fi + ;; + esac +fi + echo -e "" echo -e "${MUTED} ${NC}OpenScience" echo -e "${MUTED} by Synthetic Sciences${NC}" From 829fe5979a0b7f8df57a4e7b8160c30b16d028d0 Mon Sep 17 00:00:00 2001 From: ishaan1124 Date: Sun, 5 Jul 2026 22:53:28 +0530 Subject: [PATCH 6/8] fix(security): drop hardcoded dev host; correct managed base URL in docs share.ts no longer ships app.dev.syntheticsciences.ai in public builds; it routes through the endpoints resolver. ARCHITECTURE.md now states app.syntheticsciences.ai, matching src/endpoints.ts. --- ARCHITECTURE.md | 2 +- backend/cli/src/share/share.ts | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 242788e..2b06d3c 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -72,7 +72,7 @@ Global config lives in `~/.config/openscience/openscience.json`; project config ## Atlas integration -Atlas is a separate, closed platform. Only its client lives here. The CLI talks to it over a documented wire contract: the `synsci` model provider id, `thk_` wallet keys, and the `/api/cli/*` endpoints, with `api.syntheticsciences.ai` as the default managed base URL (`src/endpoints.ts`). Billing classification (`byok`, `managed`, `oauth-free`) is decided client-side in `src/session/billing-gate.ts`; the server is the billing authority. None of the Atlas server, its secrets, or its internal endpoints are part of this repository. +Atlas is a separate, closed platform. Only its client lives here. The CLI talks to it over a documented wire contract: the `synsci` model provider id, `thk_` wallet keys, and the `/api/cli/*` endpoints, with `app.syntheticsciences.ai` as the default managed base URL (`src/endpoints.ts`). Billing classification (`byok`, `managed`, `oauth-free`) is decided client-side in `src/session/billing-gate.ts`; the server is the billing authority. None of the Atlas server, its secrets, or its internal endpoints are part of this repository. ## Build and release diff --git a/backend/cli/src/share/share.ts b/backend/cli/src/share/share.ts index 7bac9ca..944418f 100644 --- a/backend/cli/src/share/share.ts +++ b/backend/cli/src/share/share.ts @@ -1,5 +1,5 @@ import { Bus } from "../bus" -import { Installation } from "../installation" +import { MANAGED_API_BASE } from "../endpoints" import { Session } from "../session" import { MessageV2 } from "../session/message-v2" import { Log } from "../util/log" @@ -66,11 +66,10 @@ export namespace Share { }) } - export const URL = - process.env["OPENSCIENCE_API"] ?? - (Installation.isPreview() || Installation.isLocal() - ? "https://app.dev.syntheticsciences.ai" - : "https://app.syntheticsciences.ai") + // Default to the managed base — a neutral public host resolved (and + // overridable) through src/endpoints.ts. Never ship a hardcoded *.dev.* + // host in the public build; OPENSCIENCE_API still wins for explicit overrides. + export const URL = process.env["OPENSCIENCE_API"] ?? MANAGED_API_BASE const disabled = true From d2567823f4399285ce82dc5d4d384bc040cda37c Mon Sep 17 00:00:00 2001 From: ishaan1124 Date: Sun, 5 Jul 2026 22:53:28 +0530 Subject: [PATCH 7/8] docs: refresh onboarding copy and move the install section up the landing page --- README.md | 9 ++-- frontend/landing/src/pages/Landing.tsx | 64 +++++++++++++------------- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 79928c3..b2b4669 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ npm install -g @synsci/openscience openscience ``` -The command is `openscience`, and it opens the workspace in your browser. If you would rather not install it globally, `npx synsci` does the same thing in a single step: +The command is `openscience`, and it opens the workspace in your browser. The first time you run it, a short setup walks you through how to power the models — Atlas managed models, your own provider keys, or skip and start on the free demo models. If you would rather not install it globally, `npx synsci` does the same thing in a single step: ```bash npx synsci @@ -58,7 +58,7 @@ export ANTHROPIC_API_KEY=sk-ant-... openscience ``` -`openscience` opens the workspace in your browser. Your keys stay on your machine and requests go straight to the provider. You can also add keys from the Credentials panel and pick a model from the model selector. To open the workspace in a specific project: +`openscience` opens the workspace in your browser. Your keys stay on your machine and requests go straight to the provider. You can also run `openscience keys add` to store a key from the terminal, add keys from the Credentials panel, and pick a model from the model selector. To open the workspace in a specific project: ```bash openscience ~/code/my-project @@ -69,10 +69,11 @@ openscience ~/code/my-project [Atlas](https://app.syntheticsciences.ai) is Synthetic Sciences' managed platform. It gives you a curated set of frontier models billed from a prepaid wallet, so you do not need per-provider keys, plus a persistent research graph and cloud compute. OpenScience works with Atlas but never requires it. ```bash -openscience connect login +openscience login # connect your Atlas account +openscience wallet # check your balance and top up ``` -Bring-your-own-key usage is always free and is never gated. Atlas only meters the models it serves. +Bring-your-own-key usage is always free and is never gated — Atlas only meters the models it serves. Use `openscience status` to see what you are connected to, and `openscience logout` to disconnect. ## How it works diff --git a/frontend/landing/src/pages/Landing.tsx b/frontend/landing/src/pages/Landing.tsx index bc669a8..1737f2d 100644 --- a/frontend/landing/src/pages/Landing.tsx +++ b/frontend/landing/src/pages/Landing.tsx @@ -637,6 +637,39 @@ export default function Landing() { + {/* ----------------------------- INSTALL ----------------------------- */} +
+
+
+ + Install +

Up and running in a minute.

+
+ +

+ Install with npm or the script, then run openscience. A short + setup asks how you want to power the models — Atlas managed models, your own provider keys, or the free + demo models — and the workspace opens in your browser. +

+
+
+ + + +
+
+ {/* --------------------------- HOW IT WORKS ------------------------- */} @@ -808,37 +841,6 @@ export default function Landing() { - {/* ----------------------------- INSTALL ----------------------------- */} -
-
-
- - Install -

Up and running in a minute.

-
- -

- Install with npm or the install script. Set a provider key, and the workspace opens in your browser. -

-
-
- - - -
-
- {/* ------------------------------- FAQ ------------------------------- */}
From cd5d8b921c5f8ee829e39fb7127e6359781f31a3 Mon Sep 17 00:00:00 2001 From: ishaan1124 Date: Sun, 5 Jul 2026 23:02:55 +0530 Subject: [PATCH 8/8] docs: update the docs site for the new command names Rename connect/auth/billing references to login/keys/wallet across the command reference, Atlas, quickstart, models, and security pages, add the new init/status/wallet/doctor commands, and rebuild the served public/docs bundle. --- .../docs/src/content/openscience/atlas.mdx | 26 +++++++------- .../docs/src/content/openscience/commands.mdx | 24 ++++++++----- .../docs/src/content/openscience/models.mdx | 2 +- .../src/content/openscience/quickstart.mdx | 4 +-- .../docs/src/content/openscience/security.mdx | 4 +-- .../{index-CdJSFNGj.js => index-BsAT-1zG.js} | 36 +++++++++---------- frontend/landing/public/docs/index.html | 2 +- 7 files changed, 52 insertions(+), 46 deletions(-) rename frontend/landing/public/docs/assets/{index-CdJSFNGj.js => index-BsAT-1zG.js} (97%) diff --git a/frontend/docs/src/content/openscience/atlas.mdx b/frontend/docs/src/content/openscience/atlas.mdx index 57a2979..d4fdc44 100644 --- a/frontend/docs/src/content/openscience/atlas.mdx +++ b/frontend/docs/src/content/openscience/atlas.mdx @@ -18,19 +18,19 @@ OpenScience never requires an account: bring-your-own-key usage is free and neve ```bash - openscience connect login + openscience login ``` - Opens your browser to approve the device. On headless or CI machines, pass `--no-browser` and paste a key, or run `openscience connect login --key thk_...` with a key created at `app.syntheticsciences.ai/cli`. + Opens your browser to approve the device. On headless or CI machines, pass `--no-browser` and paste a key, or run `openscience login --key thk_...` with a key created at `app.syntheticsciences.ai/cli`. ```bash - openscience connect status + openscience status ``` Shows the connected user, this device, and how many service credentials synced. ```bash - openscience connect sync + openscience sync ``` Refreshes synced service credentials after you change them on the dashboard. @@ -41,25 +41,25 @@ OpenScience never requires an account: bring-your-own-key usage is free and neve Key routing is per-provider and automatic: if you set a BYOK key for a provider, OpenScience uses it; otherwise the request goes through the Atlas managed route and debits your wallet. ```bash -openscience billing # wallet balance and current key routing -openscience billing topup # opens the Plan tab — $50 or $200, one-time or recurring monthly +openscience wallet # wallet balance and current key routing +openscience wallet topup # opens the Plan tab — $50 or $200, one-time or recurring monthly ``` Flip managed versus BYOK per surface (LLM and compute) in **Settings → Billing**. BYOK works on every plan. ## Where credentials live -Connected, your account holds the canonical copy of every synced credential; the local `~/.config/openscience/credentials.json` is a mirror you can delete and re-pull with `openscience connect sync`. In BYOK mode, keys exist only on your machine — see [Security](/openscience/security) for the storage and subprocess rules. +Connected, your account holds the canonical copy of every synced credential; the local `~/.config/openscience/credentials.json` is a mirror you can delete and re-pull with `openscience sync`. In BYOK mode, keys exist only on your machine — see [Security](/openscience/security) for the storage and subprocess rules. -## `connect` commands +## Account commands | Command | Use | | --- | --- | -| `openscience connect login` | Authenticate via browser; `--key thk_...` or `--no-browser` for headless machines. | -| `openscience connect status` | Connection, user, device, and synced credential count. | -| `openscience connect sync` | Re-pull synced service credentials from the dashboard. | -| `openscience connect devices` | List authenticated devices; revoke from the Devices tab on the dashboard. | -| `openscience connect logout` | Disconnect this machine. BYOK keeps working. | +| `openscience login` | Authenticate via browser; `--key thk_...` or `--no-browser` for headless machines. | +| `openscience status` | Connection, user, device, and synced credential count. | +| `openscience sync` | Re-pull synced service credentials from the dashboard. | +| `openscience devices` | List authenticated devices; revoke from the Devices tab on the dashboard. | +| `openscience logout` | Disconnect this machine. BYOK keeps working. | ## What's next diff --git a/frontend/docs/src/content/openscience/commands.mdx b/frontend/docs/src/content/openscience/commands.mdx index 4932fba..77dfd3b 100644 --- a/frontend/docs/src/content/openscience/commands.mdx +++ b/frontend/docs/src/content/openscience/commands.mdx @@ -39,21 +39,27 @@ Connecting an Atlas account is optional — see [Atlas](/openscience/atlas). Ope | Command | Use | | --- | --- | -| `openscience connect login` | Connect your Atlas account (browser flow, or `--key thk_…`). | -| `openscience connect status` | Show the active account, default model, synced services, and credit. | -| `openscience connect sync` | Re-pull synced credentials. | -| `openscience connect devices` | List authorized devices. | -| `openscience connect logout` | Disconnect this device from Atlas. | +| `openscience init` | First-run setup wizard — choose managed models, your own keys, or skip. Rerun anytime (alias `onboard`). | +| `openscience login` | Connect your Atlas account (browser flow, or `--key thk_…`). | +| `openscience status` | Show the active account, synced services, subscription, and wallet (alias `whoami`). | +| `openscience sync` | Re-pull synced credentials. | +| `openscience devices` | List authorized devices. | +| `openscience logout` | Disconnect this device from Atlas. | +| `openscience doctor` | Report what's configured: account, provider keys, wallet, default model. | + +`openscience connect …` still works as an alias for `login` / `logout` / `status` / `sync` / `devices`. ## Providers and routing | Command | Use | | --- | --- | -| `openscience auth` | Interactive provider sign-in (BYOK keys; OAuth where supported). | -| `openscience logout [provider]` | Log out of a connected provider. | +| `openscience keys add` | Add a provider API key (BYOK; OAuth sign-in where supported). Alias: `auth`. | +| `openscience keys signin` | Sign in with ChatGPT / Codex (subscription). | +| `openscience keys list` | List saved provider keys and active env vars. | +| `openscience keys rm` | Remove a saved provider key. | | `openscience models` | List configured providers and their models. | -| `openscience billing show` | Credit and recent managed-route usage (Atlas-connected mode). | -| `openscience billing topup` | Open the app to add credit. | +| `openscience wallet` | Wallet balance and key routing (alias `billing`). | +| `openscience wallet topup` | Open the app to add credit. | ## Agent profiles diff --git a/frontend/docs/src/content/openscience/models.mdx b/frontend/docs/src/content/openscience/models.mdx index e510bab..ef847cd 100644 --- a/frontend/docs/src/content/openscience/models.mdx +++ b/frontend/docs/src/content/openscience/models.mdx @@ -40,7 +40,7 @@ openscience run --model anthropic/claude-sonnet-5 "Clean up the plotting code" [Atlas](/openscience/atlas) is the managed platform. Connecting adds a curated set of frontier models billed from a prepaid wallet, so you can skip per-provider keys entirely: ```bash -openscience connect login # defaults to app.syntheticsciences.ai +openscience login # defaults to app.syntheticsciences.ai ``` Once connected, launching the workspace syncs your provider config and credentials, and Settings → Billing has independent managed/BYOK spend toggles for LLM calls and compute — mix routes freely, per concern. BYOK usage is always free and never gated; Atlas only meters the models it serves. diff --git a/frontend/docs/src/content/openscience/quickstart.mdx b/frontend/docs/src/content/openscience/quickstart.mdx index 6320aee..2545b7f 100644 --- a/frontend/docs/src/content/openscience/quickstart.mdx +++ b/frontend/docs/src/content/openscience/quickstart.mdx @@ -19,7 +19,7 @@ Five minutes from zero to a running research session. No account required. export ANTHROPIC_API_KEY=sk-ant-... # or OPENAI_API_KEY, GEMINI_API_KEY, ... ``` - Any provider works — bring your own key and it stays on your machine. `openscience auth` gives you an interactive sign-in for providers that support it. See [Models](/openscience/models) for routing and reasoning-effort tiers. + Any provider works — bring your own key and it stays on your machine. `openscience keys add` gives you an interactive sign-in for providers that support it. See [Models](/openscience/models) for routing and reasoning-effort tiers. ```bash @@ -44,7 +44,7 @@ Five minutes from zero to a running research session. No account required. ```bash - openscience connect login + openscience login ``` Connecting an [Atlas](/openscience/atlas) account records your research into durable graphs and unlocks a managed model route with spend controls. OpenScience never requires it. See [Connect to Atlas](/openscience/atlas). diff --git a/frontend/docs/src/content/openscience/security.mdx b/frontend/docs/src/content/openscience/security.mdx index 024ebc5..8456053 100644 --- a/frontend/docs/src/content/openscience/security.mdx +++ b/frontend/docs/src/content/openscience/security.mdx @@ -15,8 +15,8 @@ The permission system prompts you before the agent runs a command or writes a fi | Surface | Where | Notes | | --- | --- | --- | | BYOK provider keys | Environment variables or the local credential store | Never leave your machine; requests go straight to the provider. No account required. | -| Atlas session | `~/.config/openscience/config.json` | `thk_*` key created by `openscience connect login`; revocable from the dashboard. | -| Synced service credentials | `~/.config/openscience/credentials.json` | Present only when [connected to Atlas](/openscience/atlas); refresh with `openscience connect sync`. | +| Atlas session | `~/.config/openscience/config.json` | `thk_*` key created by `openscience login`; revocable from the dashboard. | +| Synced service credentials | `~/.config/openscience/credentials.json` | Present only when [connected to Atlas](/openscience/atlas); refresh with `openscience sync`. | | Native binary (curl install) | `~/.openscience/bin/openscience` | Added to PATH through your shell rc. | Override the config parent directory with `XDG_CONFIG_HOME`. diff --git a/frontend/landing/public/docs/assets/index-CdJSFNGj.js b/frontend/landing/public/docs/assets/index-BsAT-1zG.js similarity index 97% rename from frontend/landing/public/docs/assets/index-CdJSFNGj.js rename to frontend/landing/public/docs/assets/index-BsAT-1zG.js index 61b12cb..59d3f35 100644 --- a/frontend/landing/public/docs/assets/index-CdJSFNGj.js +++ b/frontend/landing/public/docs/assets/index-BsAT-1zG.js @@ -66,19 +66,19 @@ OpenScience never requires an account: bring-your-own-key usage is free and neve \`\`\`bash - openscience connect login + openscience login \`\`\` - Opens your browser to approve the device. On headless or CI machines, pass \`--no-browser\` and paste a key, or run \`openscience connect login --key thk_...\` with a key created at \`app.syntheticsciences.ai/cli\`. + Opens your browser to approve the device. On headless or CI machines, pass \`--no-browser\` and paste a key, or run \`openscience login --key thk_...\` with a key created at \`app.syntheticsciences.ai/cli\`. \`\`\`bash - openscience connect status + openscience status \`\`\` Shows the connected user, this device, and how many service credentials synced. \`\`\`bash - openscience connect sync + openscience sync \`\`\` Refreshes synced service credentials after you change them on the dashboard. @@ -89,25 +89,25 @@ OpenScience never requires an account: bring-your-own-key usage is free and neve Key routing is per-provider and automatic: if you set a BYOK key for a provider, OpenScience uses it; otherwise the request goes through the Atlas managed route and debits your wallet. \`\`\`bash -openscience billing # wallet balance and current key routing -openscience billing topup # opens the Plan tab — $50 or $200, one-time or recurring monthly +openscience wallet # wallet balance and current key routing +openscience wallet topup # opens the Plan tab — $50 or $200, one-time or recurring monthly \`\`\` Flip managed versus BYOK per surface (LLM and compute) in **Settings → Billing**. BYOK works on every plan. ## Where credentials live -Connected, your account holds the canonical copy of every synced credential; the local \`~/.config/openscience/credentials.json\` is a mirror you can delete and re-pull with \`openscience connect sync\`. In BYOK mode, keys exist only on your machine — see [Security](/openscience/security) for the storage and subprocess rules. +Connected, your account holds the canonical copy of every synced credential; the local \`~/.config/openscience/credentials.json\` is a mirror you can delete and re-pull with \`openscience sync\`. In BYOK mode, keys exist only on your machine — see [Security](/openscience/security) for the storage and subprocess rules. -## \`connect\` commands +## Account commands | Command | Use | | --- | --- | -| \`openscience connect login\` | Authenticate via browser; \`--key thk_...\` or \`--no-browser\` for headless machines. | -| \`openscience connect status\` | Connection, user, device, and synced credential count. | -| \`openscience connect sync\` | Re-pull synced service credentials from the dashboard. | -| \`openscience connect devices\` | List authenticated devices; revoke from the Devices tab on the dashboard. | -| \`openscience connect logout\` | Disconnect this machine. BYOK keeps working. | +| \`openscience login\` | Authenticate via browser; \`--key thk_...\` or \`--no-browser\` for headless machines. | +| \`openscience status\` | Connection, user, device, and synced credential count. | +| \`openscience sync\` | Re-pull synced service credentials from the dashboard. | +| \`openscience devices\` | List authenticated devices; revoke from the Devices tab on the dashboard. | +| \`openscience logout\` | Disconnect this machine. BYOK keeps working. | ## What's next @@ -125,7 +125,7 @@ Connected, your account holds the canonical copy of every synced credential; the What leaves your machine in each mode. -`,Eb='---\ntitle: "Command reference"\ndescription: "Every openscience subcommand: workspace, run, sessions, models, agents, skills, and lifecycle."\nicon: "terminal"\n---\n\nThe OpenScience command surface. For live help, run `openscience --help` and `openscience --help`.\n\nThe bare `openscience` (no arguments) starts the local server and opens the **browser workspace** in your working directory. Everything else is grouped below.\n\n## Global flags\n\n| Flag | Use |\n| --- | --- |\n| `-v, --version` | Print the installed version. |\n| `-h, --help` | Print help for a command. |\n| `--print-logs` | Stream agent diagnostics to stderr. |\n| `--log-level ` | Override the log threshold. |\n\n## Workspace and runs\n\n| Command | Use |\n| --- | --- |\n| `openscience` | Start the server and open the browser workspace. |\n| `openscience run [message..]` | One-shot prompt in the terminal; streams, then exits. |\n| `openscience session list` | List recent sessions (`-n`, `--format`). |\n\n`run` flags: `-c/--continue`, `-s/--session `, `-m/--model `, `--variant ` (provider-specific reasoning effort), `--agent `, `--format `, `-f/--file `, `--attach ` (attach to a running server, e.g. `http://localhost:4096`), `--port`, `--title `.\n\n```bash\nopenscience run "Plot the attention entropy across layers for this checkpoint"\nopenscience run -c "Now sweep the temperature and re-plot"\nopenscience run --format json "Summarize the experiment in results/" > summary.json\n```\n\n## Account\n\nConnecting an Atlas account is optional — see [Atlas](/openscience/atlas). OpenScience runs fully standalone with your own provider keys.\n\n| Command | Use |\n| --- | --- |\n| `openscience connect login` | Connect your Atlas account (browser flow, or `--key thk_…`). |\n| `openscience connect status` | Show the active account, default model, synced services, and credit. |\n| `openscience connect sync` | Re-pull synced credentials. |\n| `openscience connect devices` | List authorized devices. |\n| `openscience connect logout` | Disconnect this device from Atlas. |\n\n## Providers and routing\n\n| Command | Use |\n| --- | --- |\n| `openscience auth` | Interactive provider sign-in (BYOK keys; OAuth where supported). |\n| `openscience logout [provider]` | Log out of a connected provider. |\n| `openscience models` | List configured providers and their models. |\n| `openscience billing show` | Credit and recent managed-route usage (Atlas-connected mode). |\n| `openscience billing topup` | Open the app to add credit. |\n\n## Agent profiles\n\n| Command | Use |\n| --- | --- |\n| `openscience agent list` | Print the agent roster on this install. |\n| `openscience agent create` | Scaffold a custom agent (system prompt + tool set + routing policy). |\n\nFlags: `--path`, `--description`, `--mode `, `--tools`, `--model`. See [Agents](/openscience/agents).\n\n## Skills\n\n| Command | Use |\n| --- | --- |\n| `openscience skill list` | Show installed skills (`--all` for the bundled set). |\n| `openscience skill show ` | Print a skill\'s metadata and entrypoints. |\n| `openscience skill add ` | Install a skill (URL or `gh:owner/repo`). |\n| `openscience skill new` / `edit` / `validate` | Author, edit, and check user skills. |\n| `openscience skill remove ` | Uninstall a skill. |\n| `openscience skill set-entries ` | Update which skills surface in the `/` picker. |\n\n## Local server and protocols\n\n| Command | Use |\n| --- | --- |\n| `openscience web` | Start the server and open the browser workspace (prints the URL, e.g. `http://localhost:4096`). |\n| `openscience serve` | Headless local server — loopback-only (`127.0.0.1`), no browser. |\n| `openscience acp` | Start an Agent Client Protocol server for editors like Zed. |\n| `openscience mcp` | Manage MCP servers (`list`, `add`, `remove`, `auth`). |\n\n`web` and `serve` take `--port` and `--cors`. See [Workspace](/openscience/workspace).\n\n## GitHub and PRs\n\n| Command | Use |\n| --- | --- |\n| `openscience github` | GitHub agent for CI/Actions (`install`, `run`). |\n| `openscience pr ` | Check out a PR branch, then launch the agent on it. |\n\n## Project and lifecycle\n\n| Command | Use |\n| --- | --- |\n| `openscience project` | Pin the Atlas project root for this folder (`merge`). |\n| `openscience export` / `openscience import` | Export or import a session as JSON. |\n| `openscience generate` | Emit the OpenAPI spec for the local server to stdout. |\n| `openscience stats` | Local token-usage and cost stats. |\n| `openscience debug` | Structured diagnostics for support (`debug paths` shows data/config dirs). |\n| `openscience upgrade` | Update to the latest version. |\n| `openscience uninstall` | Remove the binary and local config. |\n| `openscience completion` | Shell completion for bash, zsh, or fish. |\n\n```bash\nopenscience upgrade\nopenscience completion zsh > ~/.zsh/completions/_openscience\n```\n\n## What\'s next\n\n\n \n The browser workspace: files, editor, terminal, inline scientific rendering.\n \n \n Credential boundary, env hygiene, the trust boundary.\n \n \n 250+ research skills and the scientific databases.\n \n \n The research agent, the specialists, and custom profiles.\n \n\n',Ab=`--- +`,Eb='---\ntitle: "Command reference"\ndescription: "Every openscience subcommand: workspace, run, sessions, models, agents, skills, and lifecycle."\nicon: "terminal"\n---\n\nThe OpenScience command surface. For live help, run `openscience --help` and `openscience --help`.\n\nThe bare `openscience` (no arguments) starts the local server and opens the **browser workspace** in your working directory. Everything else is grouped below.\n\n## Global flags\n\n| Flag | Use |\n| --- | --- |\n| `-v, --version` | Print the installed version. |\n| `-h, --help` | Print help for a command. |\n| `--print-logs` | Stream agent diagnostics to stderr. |\n| `--log-level ` | Override the log threshold. |\n\n## Workspace and runs\n\n| Command | Use |\n| --- | --- |\n| `openscience` | Start the server and open the browser workspace. |\n| `openscience run [message..]` | One-shot prompt in the terminal; streams, then exits. |\n| `openscience session list` | List recent sessions (`-n`, `--format`). |\n\n`run` flags: `-c/--continue`, `-s/--session `, `-m/--model `, `--variant ` (provider-specific reasoning effort), `--agent `, `--format `, `-f/--file `, `--attach ` (attach to a running server, e.g. `http://localhost:4096`), `--port`, `--title `.\n\n```bash\nopenscience run "Plot the attention entropy across layers for this checkpoint"\nopenscience run -c "Now sweep the temperature and re-plot"\nopenscience run --format json "Summarize the experiment in results/" > summary.json\n```\n\n## Account\n\nConnecting an Atlas account is optional — see [Atlas](/openscience/atlas). OpenScience runs fully standalone with your own provider keys.\n\n| Command | Use |\n| --- | --- |\n| `openscience init` | First-run setup wizard — choose managed models, your own keys, or skip. Rerun anytime (alias `onboard`). |\n| `openscience login` | Connect your Atlas account (browser flow, or `--key thk_…`). |\n| `openscience status` | Show the active account, synced services, subscription, and wallet (alias `whoami`). |\n| `openscience sync` | Re-pull synced credentials. |\n| `openscience devices` | List authorized devices. |\n| `openscience logout` | Disconnect this device from Atlas. |\n| `openscience doctor` | Report what\'s configured: account, provider keys, wallet, default model. |\n\n`openscience connect …` still works as an alias for `login` / `logout` / `status` / `sync` / `devices`.\n\n## Providers and routing\n\n| Command | Use |\n| --- | --- |\n| `openscience keys add` | Add a provider API key (BYOK; OAuth sign-in where supported). Alias: `auth`. |\n| `openscience keys signin` | Sign in with ChatGPT / Codex (subscription). |\n| `openscience keys list` | List saved provider keys and active env vars. |\n| `openscience keys rm` | Remove a saved provider key. |\n| `openscience models` | List configured providers and their models. |\n| `openscience wallet` | Wallet balance and key routing (alias `billing`). |\n| `openscience wallet topup` | Open the app to add credit. |\n\n## Agent profiles\n\n| Command | Use |\n| --- | --- |\n| `openscience agent list` | Print the agent roster on this install. |\n| `openscience agent create` | Scaffold a custom agent (system prompt + tool set + routing policy). |\n\nFlags: `--path`, `--description`, `--mode `, `--tools`, `--model`. See [Agents](/openscience/agents).\n\n## Skills\n\n| Command | Use |\n| --- | --- |\n| `openscience skill list` | Show installed skills (`--all` for the bundled set). |\n| `openscience skill show ` | Print a skill\'s metadata and entrypoints. |\n| `openscience skill add ` | Install a skill (URL or `gh:owner/repo`). |\n| `openscience skill new` / `edit` / `validate` | Author, edit, and check user skills. |\n| `openscience skill remove ` | Uninstall a skill. |\n| `openscience skill set-entries ` | Update which skills surface in the `/` picker. |\n\n## Local server and protocols\n\n| Command | Use |\n| --- | --- |\n| `openscience web` | Start the server and open the browser workspace (prints the URL, e.g. `http://localhost:4096`). |\n| `openscience serve` | Headless local server — loopback-only (`127.0.0.1`), no browser. |\n| `openscience acp` | Start an Agent Client Protocol server for editors like Zed. |\n| `openscience mcp` | Manage MCP servers (`list`, `add`, `remove`, `auth`). |\n\n`web` and `serve` take `--port` and `--cors`. See [Workspace](/openscience/workspace).\n\n## GitHub and PRs\n\n| Command | Use |\n| --- | --- |\n| `openscience github` | GitHub agent for CI/Actions (`install`, `run`). |\n| `openscience pr ` | Check out a PR branch, then launch the agent on it. |\n\n## Project and lifecycle\n\n| Command | Use |\n| --- | --- |\n| `openscience project` | Pin the Atlas project root for this folder (`merge`). |\n| `openscience export` / `openscience import` | Export or import a session as JSON. |\n| `openscience generate` | Emit the OpenAPI spec for the local server to stdout. |\n| `openscience stats` | Local token-usage and cost stats. |\n| `openscience debug` | Structured diagnostics for support (`debug paths` shows data/config dirs). |\n| `openscience upgrade` | Update to the latest version. |\n| `openscience uninstall` | Remove the binary and local config. |\n| `openscience completion` | Shell completion for bash, zsh, or fish. |\n\n```bash\nopenscience upgrade\nopenscience completion zsh > ~/.zsh/completions/_openscience\n```\n\n## What\'s next\n\n\n \n The browser workspace: files, editor, terminal, inline scientific rendering.\n \n \n Credential boundary, env hygiene, the trust boundary.\n \n \n 250+ research skills and the scientific databases.\n \n \n The research agent, the specialists, and custom profiles.\n \n\n',Ab=`--- title: "OpenScience" description: "The open-source AI workbench for scientific research. Give it a goal — it reads the literature, writes and runs code, runs the experiments, and writes up what it found." icon: "flask-conical" @@ -245,7 +245,7 @@ openscience run --model anthropic/claude-sonnet-5 "Clean up the plotting code" [Atlas](/openscience/atlas) is the managed platform. Connecting adds a curated set of frontier models billed from a prepaid wallet, so you can skip per-provider keys entirely: \`\`\`bash -openscience connect login # defaults to app.syntheticsciences.ai +openscience login # defaults to app.syntheticsciences.ai \`\`\` Once connected, launching the workspace syncs your provider config and credentials, and Settings → Billing has independent managed/BYOK spend toggles for LLM calls and compute — mix routes freely, per concern. BYOK usage is always free and never gated; Atlas only meters the models it serves. @@ -296,7 +296,7 @@ Five minutes from zero to a running research session. No account required. export ANTHROPIC_API_KEY=sk-ant-... # or OPENAI_API_KEY, GEMINI_API_KEY, ... \`\`\` - Any provider works — bring your own key and it stays on your machine. \`openscience auth\` gives you an interactive sign-in for providers that support it. See [Models](/openscience/models) for routing and reasoning-effort tiers. + Any provider works — bring your own key and it stays on your machine. \`openscience keys add\` gives you an interactive sign-in for providers that support it. See [Models](/openscience/models) for routing and reasoning-effort tiers. \`\`\`bash @@ -321,7 +321,7 @@ Five minutes from zero to a running research session. No account required. \`\`\`bash - openscience connect login + openscience login \`\`\` Connecting an [Atlas](/openscience/atlas) account records your research into durable graphs and unlocks a managed model route with spend controls. OpenScience never requires it. See [Connect to Atlas](/openscience/atlas). @@ -346,7 +346,7 @@ openscience skill list # installed skills Every subcommand: runs, sessions, skills, server, lifecycle. -`,zb='---\ntitle: "Security"\ndescription: "The trust boundary, credential storage, and subprocess environment hygiene — in an open-source agent you can audit end to end."\nicon: "shield-check"\n---\n\nOpenScience is open source under Apache-2.0, so the whole security model below is auditable in the [repository](https://github.com/synthetic-sciences/openscience). The agent runs locally with the same filesystem and shell access you have. Two principles anchor the design: keep credentials out of subprocesses that do not need them, and make the trust boundary explicit instead of pretending the agent is a sandbox.\n\n## The agent is not a sandbox\n\nThe permission system prompts you before the agent runs a command or writes a file. That keeps you aware of what it is doing — it is not an isolation boundary. The agent can read, write, and execute anywhere your user can. For real isolation, run OpenScience inside a container or a VM.\n\n## Credential storage\n\n| Surface | Where | Notes |\n| --- | --- | --- |\n| BYOK provider keys | Environment variables or the local credential store | Never leave your machine; requests go straight to the provider. No account required. |\n| Atlas session | `~/.config/openscience/config.json` | `thk_*` key created by `openscience connect login`; revocable from the dashboard. |\n| Synced service credentials | `~/.config/openscience/credentials.json` | Present only when [connected to Atlas](/openscience/atlas); refresh with `openscience connect sync`. |\n| Native binary (curl install) | `~/.openscience/bin/openscience` | Added to PATH through your shell rc. |\n\nOverride the config parent directory with `XDG_CONFIG_HOME`.\n\n## Subprocess environment allow-list\n\nWhen the agent shells out, it rebuilds the subprocess environment from a curated allow-list rather than inheriting your full shell. Provider keys stay out of commands that have no business seeing them.\n\n**Always passed through:** `PATH`, `HOME`, `USER`, `SHELL`, `TERM`, `LANG`, `LC_*`, `TMPDIR`, `XDG_*`, `EDITOR`, `VISUAL`.\n\n**Passed through only when a subprocess needs them:** `HF_TOKEN`, `WANDB_API_KEY`, `MODAL_TOKEN_ID`, `MODAL_TOKEN_SECRET`, `LAMBDA_API_KEY`, `RUNPOD_API_KEY`, `PRIME_INTELLECT_API_KEY`, `TENSORPOOL_API_KEY`, `VAST_API_KEY`, `TINKER_API_KEY`, `LANGSMITH_API_KEY`, `PINECONE_API_KEY`, `TOGETHER_API_KEY`, `GROQ_API_KEY`, `FIREWORKS_API_KEY`, `OPENROUTER_API_KEY`.\n\n**Explicitly filtered out, even if set in your shell:** `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_GENERATIVE_AI_API_KEY`, `GEMINI_API_KEY`. The agent talks to model providers itself; subprocesses do not need these keys.\n\n## Output redaction\n\nKnown credential patterns are redacted from agent output before it lands in a transcript. If you spot an unredacted secret, report it (see below).\n\n## Server mode\n\nServer mode is opt-in. The server binds to localhost (127.0.0.1) only and enforces a Host and Origin allowlist to block DNS-rebinding and cross-origin requests. It is not built for remote exposure — if you tunnel or reverse-proxy it, securing that exposure is on you.\n\n## What leaves your machine\n\n- Prompts and responses sent to your model provider, governed by that provider\'s policy.\n- Nothing else, in BYOK mode. If you [connect to Atlas](/openscience/atlas), synced credentials and usage metering are held against your account.\n\nSource files stay local unless the agent explicitly uploads them through a tool you approve, and local environment variables outside the allow-list above are never forwarded.\n\n## Reporting a vulnerability\n\nReport security issues through the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/synthetic-sciences/openscience/security/advisories/new) form — not on public issue trackers. If you do not hear back within six business days, email security@syntheticsciences.ai.\n',_b='---\ntitle: "Sessions & one-shot runs"\ndescription: "One agent conversation: history, tool calls, and a working directory. Create, resume, attach, and export."\nicon: "layers"\n---\n\nA **session** is a single agent conversation: a thread of prompts and replies, the tool calls the agent made, and the working directory those calls ran against. Sessions are stored on disk, so everything below works offline and without an account.\n\n## Start a session\n\n| Entrypoint | Use |\n| --- | --- |\n| `openscience` | Open the [browser workspace](/openscience/workspace) in the current directory. |\n| `openscience run [message..]` | Send one prompt from the terminal, stream the result, and exit. Good for pipelines, CI, and git hooks. |\n| `openscience serve` | Start a headless server (no browser) for `run --attach` to target. |\n\nThe workspace is interactive; `openscience run` is the one to script. Each produces a session you can resume from either surface.\n\n## One-shot runs\n\n```bash\nopenscience run "Set up a DFT optimization for this structure" -f data/sample.cif\ngit diff | openscience run "Review this diff for race conditions"\n```\n\nPiped stdin is appended to the message. `openscience run` supports:\n\n| Flag | Use |\n| --- | --- |\n| `-c, --continue` | Continue the most recent session. |\n| `-s, --session ` | Continue a specific session by id. |\n| `-m, --model ` | Model for this run, e.g. `anthropic/claude-opus-4-8`. See [Models](/openscience/models). |\n| `--variant ` | Reasoning-effort tier (`high`, `max`, `minimal`; model-dependent). |\n| `--agent ` | Run a specific primary agent. See [Agents](/openscience/agents). |\n| `--command ` | Run a custom command, with the message as its arguments. |\n| `-f, --file ` | Attach a local file to the message (repeatable). |\n| `--title ` | Title for the session in `session list`. |\n| `--format ` | `json` emits one JSON event per line (`tool_use`, `step_start`, `step_finish`, `text`, `error`), tagged with the session id — pipe it to a file and parse line by line. |\n| `--attach ` | Send the prompt to a running server instead of starting one. |\n| `--port ` | Port for the throwaway local server (random by default). |\n\nTo pick up a file, always use `-f`; `--attach` targets a server, it does not fetch documents.\n\n## Continue or resume\n\n```bash\nopenscience session list # recent sessions (-n 10 to cap, --format json)\nopenscience run -c "Now add tests for the refactored module"\nopenscience run -s ses_8f2ka91xk "Rerun the sweep with lr=3e-4"\n```\n\n`session list` prints a table of ids, titles, and update times (paged through `less` in a terminal). In the workspace, the same sessions appear in the session history pane, where you can also queue prompts and undo from any message.\n\n## Attach to a running server\n\nLeave `openscience serve` (or the workspace) running and drive it from another terminal:\n\n```bash\nopenscience run --attach http://localhost:4096 "Summarize today\'s results" # new session on the server\nopenscience run --attach http://localhost:4096 -s ses_8f2ka91xk "Continue" # a specific session (-c: latest)\n```\n\nThe run shares the server\'s sessions, so work started in the browser continues from the terminal and vice versa.\n\n## Export and import\n\n```bash\nopenscience export ses_8f2ka91xk > session.json # no id: interactive picker\nopenscience import session.json\n```\n\n`export` writes the full session as JSON to stdout; `import` loads it on another machine. Useful for sharing reproductions or attaching a transcript to an issue.\n\n## What\'s next\n\n\n \n The browser surface for the same sessions.\n \n \n Per-run and per-session model choice.\n \n \n Primary agents, specialists, and plan mode.\n \n \n The full command reference.\n \n\n',Ob=`--- +`,zb='---\ntitle: "Security"\ndescription: "The trust boundary, credential storage, and subprocess environment hygiene — in an open-source agent you can audit end to end."\nicon: "shield-check"\n---\n\nOpenScience is open source under Apache-2.0, so the whole security model below is auditable in the [repository](https://github.com/synthetic-sciences/openscience). The agent runs locally with the same filesystem and shell access you have. Two principles anchor the design: keep credentials out of subprocesses that do not need them, and make the trust boundary explicit instead of pretending the agent is a sandbox.\n\n## The agent is not a sandbox\n\nThe permission system prompts you before the agent runs a command or writes a file. That keeps you aware of what it is doing — it is not an isolation boundary. The agent can read, write, and execute anywhere your user can. For real isolation, run OpenScience inside a container or a VM.\n\n## Credential storage\n\n| Surface | Where | Notes |\n| --- | --- | --- |\n| BYOK provider keys | Environment variables or the local credential store | Never leave your machine; requests go straight to the provider. No account required. |\n| Atlas session | `~/.config/openscience/config.json` | `thk_*` key created by `openscience login`; revocable from the dashboard. |\n| Synced service credentials | `~/.config/openscience/credentials.json` | Present only when [connected to Atlas](/openscience/atlas); refresh with `openscience sync`. |\n| Native binary (curl install) | `~/.openscience/bin/openscience` | Added to PATH through your shell rc. |\n\nOverride the config parent directory with `XDG_CONFIG_HOME`.\n\n## Subprocess environment allow-list\n\nWhen the agent shells out, it rebuilds the subprocess environment from a curated allow-list rather than inheriting your full shell. Provider keys stay out of commands that have no business seeing them.\n\n**Always passed through:** `PATH`, `HOME`, `USER`, `SHELL`, `TERM`, `LANG`, `LC_*`, `TMPDIR`, `XDG_*`, `EDITOR`, `VISUAL`.\n\n**Passed through only when a subprocess needs them:** `HF_TOKEN`, `WANDB_API_KEY`, `MODAL_TOKEN_ID`, `MODAL_TOKEN_SECRET`, `LAMBDA_API_KEY`, `RUNPOD_API_KEY`, `PRIME_INTELLECT_API_KEY`, `TENSORPOOL_API_KEY`, `VAST_API_KEY`, `TINKER_API_KEY`, `LANGSMITH_API_KEY`, `PINECONE_API_KEY`, `TOGETHER_API_KEY`, `GROQ_API_KEY`, `FIREWORKS_API_KEY`, `OPENROUTER_API_KEY`.\n\n**Explicitly filtered out, even if set in your shell:** `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_GENERATIVE_AI_API_KEY`, `GEMINI_API_KEY`. The agent talks to model providers itself; subprocesses do not need these keys.\n\n## Output redaction\n\nKnown credential patterns are redacted from agent output before it lands in a transcript. If you spot an unredacted secret, report it (see below).\n\n## Server mode\n\nServer mode is opt-in. The server binds to localhost (127.0.0.1) only and enforces a Host and Origin allowlist to block DNS-rebinding and cross-origin requests. It is not built for remote exposure — if you tunnel or reverse-proxy it, securing that exposure is on you.\n\n## What leaves your machine\n\n- Prompts and responses sent to your model provider, governed by that provider\'s policy.\n- Nothing else, in BYOK mode. If you [connect to Atlas](/openscience/atlas), synced credentials and usage metering are held against your account.\n\nSource files stay local unless the agent explicitly uploads them through a tool you approve, and local environment variables outside the allow-list above are never forwarded.\n\n## Reporting a vulnerability\n\nReport security issues through the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/synthetic-sciences/openscience/security/advisories/new) form — not on public issue trackers. If you do not hear back within six business days, email security@syntheticsciences.ai.\n',_b='---\ntitle: "Sessions & one-shot runs"\ndescription: "One agent conversation: history, tool calls, and a working directory. Create, resume, attach, and export."\nicon: "layers"\n---\n\nA **session** is a single agent conversation: a thread of prompts and replies, the tool calls the agent made, and the working directory those calls ran against. Sessions are stored on disk, so everything below works offline and without an account.\n\n## Start a session\n\n| Entrypoint | Use |\n| --- | --- |\n| `openscience` | Open the [browser workspace](/openscience/workspace) in the current directory. |\n| `openscience run [message..]` | Send one prompt from the terminal, stream the result, and exit. Good for pipelines, CI, and git hooks. |\n| `openscience serve` | Start a headless server (no browser) for `run --attach` to target. |\n\nThe workspace is interactive; `openscience run` is the one to script. Each produces a session you can resume from either surface.\n\n## One-shot runs\n\n```bash\nopenscience run "Set up a DFT optimization for this structure" -f data/sample.cif\ngit diff | openscience run "Review this diff for race conditions"\n```\n\nPiped stdin is appended to the message. `openscience run` supports:\n\n| Flag | Use |\n| --- | --- |\n| `-c, --continue` | Continue the most recent session. |\n| `-s, --session ` | Continue a specific session by id. |\n| `-m, --model ` | Model for this run, e.g. `anthropic/claude-opus-4-8`. See [Models](/openscience/models). |\n| `--variant ` | Reasoning-effort tier (`high`, `max`, `minimal`; model-dependent). |\n| `--agent ` | Run a specific primary agent. See [Agents](/openscience/agents). |\n| `--command ` | Run a custom command, with the message as its arguments. |\n| `-f, --file ` | Attach a local file to the message (repeatable). |\n| `--title ` | Title for the session in `session list`. |\n| `--format ` | `json` emits one JSON event per line (`tool_use`, `step_start`, `step_finish`, `text`, `error`), tagged with the session id — pipe it to a file and parse line by line. |\n| `--attach ` | Send the prompt to a running server instead of starting one. |\n| `--port ` | Port for the throwaway local server (random by default). |\n\nTo pick up a file, always use `-f`; `--attach` targets a server, it does not fetch documents.\n\n## Continue or resume\n\n```bash\nopenscience session list # recent sessions (-n 10 to cap, --format json)\nopenscience run -c "Now add tests for the refactored module"\nopenscience run -s ses_8f2ka91xk "Rerun the sweep with lr=3e-4"\n```\n\n`session list` prints a table of ids, titles, and update times (paged through `less` in a terminal). In the workspace, the same sessions appear in the session history pane, where you can also queue prompts and undo from any message.\n\n## Attach to a running server\n\nLeave `openscience serve` (or the workspace) running and drive it from another terminal:\n\n```bash\nopenscience run --attach http://localhost:4096 "Summarize today\'s results" # new session on the server\nopenscience run --attach http://localhost:4096 -s ses_8f2ka91xk "Continue" # a specific session (-c: latest)\n```\n\nThe run shares the server\'s sessions, so work started in the browser continues from the terminal and vice versa.\n\n## Export and import\n\n```bash\nopenscience export ses_8f2ka91xk > session.json # no id: interactive picker\nopenscience import session.json\n```\n\n`export` writes the full session as JSON to stdout; `import` loads it on another machine. Useful for sharing reproductions or attaching a transcript to an issue.\n\n## What\'s next\n\n\n \n The browser surface for the same sessions.\n \n \n Per-run and per-session model choice.\n \n \n Primary agents, specialists, and plan mode.\n \n \n The full command reference.\n \n\n',Ob=`--- title: "Skills" description: "250+ bundled research skills, direct access to around 30 scientific databases, and commands for installing, writing, and pinning skills." icon: "book-open" diff --git a/frontend/landing/public/docs/index.html b/frontend/landing/public/docs/index.html index 1cf3b63..377d134 100644 --- a/frontend/landing/public/docs/index.html +++ b/frontend/landing/public/docs/index.html @@ -14,7 +14,7 @@ - +