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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 43 additions & 12 deletions docs/components/quickstartShared.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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') {
Expand Down Expand Up @@ -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}"
Expand All @@ -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`
}
Expand Down Expand Up @@ -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" <<EOF
[scm]
provider = "${scm}"
Expand All @@ -297,8 +316,12 @@ llm_api_key = "\${${a.keyEnv}}"${reviewer}
path = "\${PROJECT}"
enabled = true
EOF
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`
}
Expand All @@ -323,8 +346,8 @@ ${a.cli}
# 2) install bubo
${installPwsh}

# 3) initialise + write config
bubo init
# 3) create the workspace, write config, then template the agent profile
bubo init --no-agent-config
$root = if ($env:BUBO_ROOT) { $env:BUBO_ROOT } else { "$env:USERPROFILE\\.local\\share\\bubo" }
@"
[scm]
Expand All @@ -341,8 +364,12 @@ llm_api_key = "$env:${a.keyEnv}"${reviewerPwsh}
path = "$PROJECT"
enabled = true
"@ | Set-Content -Path "$root\\config\\env.toml" -Encoding utf8
bubo init

# 4) authenticate the review agent (logs in here — the key never enters the agent's env)
${authPwsh}

# 4) verify + run the first (dry-run) review
# 5) verify + run the first (dry-run) review
bubo doctor
bubo-poller`
}
Expand All @@ -368,8 +395,8 @@ ${a.cli}
# 2) install bubo
${INSTALL_LINE[install]}

# 3) initialise + write config
bubo init
# 3) create the workspace, write config, then template the agent profile from it
bubo init --no-agent-config
CFG="\${BUBO_ROOT:-$HOME/.local/share/bubo}/config/env.toml"
cat > "$CFG" <<EOF
[scm]
Expand All @@ -386,8 +413,12 @@ llm_api_key = "\${${a.keyEnv}}"${reviewer}
path = "\${PROJECT}"
enabled = true
EOF
bubo init

# 4) authenticate the review agent (logs in here — the key never enters the agent's env)
${authBash}

# 4) verify + run the first (dry-run) review
# 5) verify + run the first (dry-run) review
bubo doctor
bubo-poller`
}
26 changes: 23 additions & 3 deletions docs/components/recipes/compose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,23 @@ ${af.configBlock}
path = "${sf.projectPath}"
enabled = true`

const keyEnv = af.keyEnv
const shellIsPwsh = OS_FRAG[os].shell === 'powershell'
const noLoginNote =
agent === 'claude'
? '# Claude brings its own login — run `claude` once to sign in before the first review.'
: '# The gateway key reaches the agent via LLM_API_KEY (base_url mode) — no separate login.'
const agentAuth =
agent === 'codex'
? shellIsPwsh
? `$env:${keyEnv} | codex login --with-api-key`
: `printf '%s' "$${keyEnv}" | codex login --with-api-key`
: noLoginNote
const agentAuthDocker = (home: string, image: string) =>
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,
Expand All @@ -43,6 +60,8 @@ enabled = true`
agentCliName: af.cliName,
os: OS_FRAG[os],
toml,
agentAuth,
agentAuthDocker,
}

const gatewayLine =
Expand Down Expand Up @@ -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).
</install>

<report>
Expand Down
6 changes: 4 additions & 2 deletions docs/components/recipes/docker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -59,6 +59,8 @@ EOF`
return `${ctx.os.exportLine(ctx.scmEnv, `<${ctx.scmPrefix}>`)}
${ctx.os.exportLine(ctx.agentKeyEnv, `<your-${ctx.agentKeyName.toLowerCase()} key>`)}

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`
},
}
5 changes: 4 additions & 1 deletion docs/components/recipes/pip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, `<your-${ctx.agentKeyName.toLowerCase()} key>`)}

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`,
}
6 changes: 6 additions & 0 deletions docs/components/recipes/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
5 changes: 4 additions & 1 deletion docs/components/recipes/uv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, `<your-${ctx.agentKeyName.toLowerCase()} key>`)}

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`,
}