diff --git a/docs/components/quickstartShared.tsx b/docs/components/quickstartShared.tsx index b885814..ac11a2d 100644 --- a/docs/components/quickstartShared.tsx +++ b/docs/components/quickstartShared.tsx @@ -192,6 +192,21 @@ export function buildScript(agent: Agent, os: OS, scm: Scm, install: Method): st const a = AGENT[agent] const s = SCM[scm] + // Agent auth: the poller strips the LLM key from the review agent's env, so the + // agent must carry its own login. Codex logs in from the key (writes auth.json, + // read back via the allowlisted CODEX_HOME); Claude is a custom reviewer_command + // that brings its own login. + const isCodex = agent === 'codex' + const claudeNote = + '# Claude brings its own login — run `claude` once to sign in before the first review.' + const authBash = isCodex + ? `printf '%s' "$${a.keyEnv}" | codex login --with-api-key` + : claudeNote + const authPwsh = isCodex ? `$env:${a.keyEnv} | codex login --with-api-key` : claudeNote + const authDocker = isCodex + ? `brun sh -c 'printf "%s" "$${a.keyEnv}" | codex login --with-api-key'` + : '# Claude brings its own login — `brun claude` (or exec into the container) to sign in first.' + // Docker → bubo's image is BYO-agent, so derive one with the CLI baked in and // persist /home/bubo (config + agent profile + SQLite) via one bind mount. if (install === 'docker') { @@ -225,8 +240,8 @@ docker build -t bubo-local . # 2) run bubo in the container, persisting its home function brun { docker run --rm -v "$WORKDIR\\home:/home/bubo" -e ${a.keyEnv} -e ${s.env} bubo-local @args } -# 3) initialise, then write config -brun bubo init +# 3) create the workspace, write config, then template the agent profile from it +brun bubo init --no-agent-config @" [scm] provider = "${scm}" @@ -242,8 +257,12 @@ llm_api_key = "$env:${a.keyEnv}"${reviewerPwsh} path = "$PROJECT" enabled = true "@ | Set-Content -Path "$WORKDIR\\home\\.local\\share\\bubo\\config\\env.toml" -Encoding utf8 +brun bubo init + +# 4) authenticate the review agent (logs in here — the key never enters the agent's env) +${authDocker} -# 4) verify + first (dry-run) review +# 5) verify + first (dry-run) review brun bubo doctor brun bubo-poller` } @@ -280,8 +299,8 @@ brun() { -e ${a.keyEnv} -e ${s.env} bubo-local "$@" } -# 3) initialise, then write config -brun bubo init +# 3) create the workspace, write config, then template the agent profile from it +brun bubo init --no-agent-config cat > "$WORKDIR/home/.local/share/bubo/config/env.toml" < "$CFG" < + agent === 'codex' + ? `docker run --rm -v "${home}:/home/bubo" -e ${keyEnv} ${image} sh -c 'printf "%s" "$${keyEnv}" | codex login --with-api-key'` + : noLoginNote + const ctx: Ctx = { scmEnv: SCM[scm].env, scmPrefix: SCM[scm].prefix, @@ -43,6 +60,8 @@ enabled = true` agentCliName: af.cliName, os: OS_FRAG[os], toml, + agentAuth, + agentAuthDocker, } const gatewayLine = @@ -125,9 +144,10 @@ On the target machine, in order: 1. **Validate** — parse the context, probe \`remote_host\` if remote, change nothing; then wait for the gate phrase \`install bubo\`. 2. **Prerequisites** — install for the target OS: \`uv\` + \`git\` + the agent CLI, or Docker. 3. **Bubo** — install via the chosen method from \`source\` at \`version\`. -4. **Configure** — run \`bubo init\`, then write \`env.toml\` from the context (scm + token, agent + key, repository, \`dry_run\`). -5. **Verify** — run \`bubo doctor\`; resolve any failure. -6. **Schedule** — unless \`poll\` is \`off\`, run ${tick} every \`poll\` via ${sched} (one cycle per run). +4. **Configure** — run \`bubo init --no-agent-config\`, write \`env.toml\` from the context (scm + token, agent + key, repository, \`dry_run\`), then run \`bubo init\` to template the agent profile from it. +5. **Authenticate the agent** — the default Codex agent logs in from the key (\`codex login --with-api-key\`, key on stdin); a custom \`reviewer_command\` (e.g. Claude) brings its own login; a \`llm_base_url\` gateway needs none. Skip if the target already authenticates the agent. +6. **Verify** — run \`bubo doctor\`; resolve any failure. +7. **Schedule** — unless \`poll\` is \`off\`, run ${tick} every \`poll\` via ${sched} (one cycle per run). diff --git a/docs/components/recipes/docker.ts b/docs/components/recipes/docker.ts index 28259f1..3e5920f 100644 --- a/docs/components/recipes/docker.ts +++ b/docs/components/recipes/docker.ts @@ -42,13 +42,13 @@ docker build -t bubo-local .` configCode: (ctx) => { if (ctx.os.shell === 'powershell') { return `New-Item -ItemType Directory -Force -Path "${HOME_PWSH}" | Out-Null -docker run --rm -v "${HOME_PWSH}:/home/bubo" bubo-local bubo init +docker run --rm -v "${HOME_PWSH}:/home/bubo" bubo-local bubo init --no-agent-config @" ${ctx.toml} "@ | Set-Content -Path "${HOME_PWSH}\\.local\\share\\bubo\\config\\env.toml" -Encoding utf8` } return `mkdir -p "${HOME_BASH}" -docker run --rm -v "${HOME_BASH}:/home/bubo" bubo-local bubo init +docker run --rm -v "${HOME_BASH}:/home/bubo" bubo-local bubo init --no-agent-config cat > "${HOME_BASH}/.local/share/bubo/config/env.toml" <<'EOF' ${ctx.toml} @@ -59,6 +59,8 @@ EOF` return `${ctx.os.exportLine(ctx.scmEnv, `<${ctx.scmPrefix}>`)} ${ctx.os.exportLine(ctx.agentKeyEnv, ``)} +docker run --rm -v "${home}:/home/bubo" bubo-local bubo init # template the agent profile from the config +${ctx.agentAuthDocker(home, 'bubo-local')} docker run --rm -v "${home}:/home/bubo" -e ${ctx.scmEnv} -e ${ctx.agentKeyEnv} bubo-local bubo-poller` }, } diff --git a/docs/components/recipes/pip.ts b/docs/components/recipes/pip.ts index f7f23bd..a396a05 100644 --- a/docs/components/recipes/pip.ts +++ b/docs/components/recipes/pip.ts @@ -12,12 +12,15 @@ export const pip: InstallFragment = { ], prereqInstall: (ctx) => ctx.os.prereqInstall(ctx.agentCli), installCode: () => `pip install bubo`, - initIntro: 'Run bubo init to seed the config, then open it and fill in the minimum:', + initIntro: + 'Run bubo init --no-agent-config to seed the config, then open it and fill in the minimum:', configCode: (ctx) => `# ${ctx.os.configPath} ${ctx.toml}`, runCode: (ctx) => `${ctx.os.exportLine(ctx.scmEnv, `<${ctx.scmPrefix}>`)} ${ctx.os.exportLine(ctx.agentKeyEnv, ``)} +bubo init # template the agent profile from the config you just edited +${ctx.agentAuth} bubo doctor # checks workspace, config, DB, and the agent profile bubo-poller # one poll cycle — dry-run by default, so it posts nothing`, } diff --git a/docs/components/recipes/types.ts b/docs/components/recipes/types.ts index 28e3aee..cb1a99c 100644 --- a/docs/components/recipes/types.ts +++ b/docs/components/recipes/types.ts @@ -30,6 +30,12 @@ export type Ctx = { agentCliName: string os: OsFragment toml: string + // Agent auth: the poller strips the LLM key from the review agent's env, so the + // agent carries its own login. Codex logs in from the key; Claude brings its own + // login; a base_url gateway reads the key from the env. `agentAuth` is the local + // shell line; `agentAuthDocker` is the in-container form. + agentAuth: string + agentAuthDocker: (home: string, image: string) => string } export type ScmFragment = { diff --git a/docs/components/recipes/uv.ts b/docs/components/recipes/uv.ts index cfde11c..b2fbea9 100644 --- a/docs/components/recipes/uv.ts +++ b/docs/components/recipes/uv.ts @@ -12,12 +12,15 @@ export const uv: InstallFragment = { ], prereqInstall: (ctx) => ctx.os.prereqInstall(ctx.agentCli), installCode: () => `uv tool install bubo`, - initIntro: 'Run bubo init to seed the config, then open it and fill in the minimum:', + initIntro: + 'Run bubo init --no-agent-config to seed the config, then open it and fill in the minimum:', configCode: (ctx) => `# ${ctx.os.configPath} ${ctx.toml}`, runCode: (ctx) => `${ctx.os.exportLine(ctx.scmEnv, `<${ctx.scmPrefix}>`)} ${ctx.os.exportLine(ctx.agentKeyEnv, ``)} +bubo init # template the agent profile from the config you just edited +${ctx.agentAuth} bubo doctor # checks workspace, config, DB, and the agent profile bubo-poller # one poll cycle — dry-run by default, so it posts nothing`, }