Skip to content

feat: new onboarding flow#7266

Merged
lifeizhou-ap merged 47 commits intomainfrom
lifei/simplify_onboarding_flow
Mar 17, 2026
Merged

feat: new onboarding flow#7266
lifeizhou-ap merged 47 commits intomainfrom
lifei/simplify_onboarding_flow

Conversation

@lifeizhou-ap
Copy link
Copy Markdown
Collaborator

@lifeizhou-ap lifeizhou-ap commented Feb 17, 2026

Key changes:

  • Two paths for users to start to reduce decision fatigue. (old flow: 6 options in one page and with multiple recommend badges)
  • Contents expand inline below the cards to keep user stay in one place instead of using modal or navigating to new screen.
  • Having a success page with the privacy choice.  In the old flow, the privacy choice is almost hidden at the end of the page so that user cannot see it.
  • Using the dropdown with auto completion for users to easily find the providers.  Also in each provider list the important field for user to enter and provide the "get api key" instructions for major providers
  • Using provider default model to reduce frictions so that users can use goose quickly

Type of Change

  • Feature
  • Bug fix
  • Refactor / Code quality
  • Performance improvement
  • Documentation
  • Tests
  • Security fix
  • Build / Release
  • Other (specify below)

Testing

Manual testing and unit test

New Experience videos

onboarding_nanogpt.mov
onboarding_local_model.mov
Screen.Recording.2026-03-16.at.2.36.16.pm.mov

* main: (73 commits)
  dev: add cmake to hermitized env (#7399)
  refactor: remove allows_unlisted_models flag, always allow custom model entry (#7255)
  feat: expose context window utilization to agent via MOIM (#7418)
  Small model naming (#7394)
  chore(deps): bump ajv in /documentation (#7416)
  doc: groq models (#7404)
  Client settings (#7381)
  Fix settings tabs getting cut off in narrow windows (#7379)
  docs: voice dictation updates (#7396)
  [docs] Add Excalidraw MCP App Tutorial (#7401)
  Post release checklist as a comment on release PRs (#7307)
  unique api key (#7391)
  fix: use correct colors for download progress bar (#7390)
  Add local model settings access from bottom bar model menu (#7378)
  Change Recipe Security Scanner API key (#7387)
  switch Ask AI Discord bot from openrouter to anthropic (#7386)
  feat(ui): show token counts directly for "free" providers (#7383)
  Update creator note (#7384)
  Remove display_name from local model API and use model ID everywhere (#7382)
  fix(summon): stop MOIM from telling models to sleep while waiting for tasks (#7377)
  ...
@lifeizhou-ap lifeizhou-ap marked this pull request as ready for review February 23, 2026 06:48
Copilot AI review requested due to automatic review settings February 24, 2026 06:41
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 34 out of 34 changed files in this pull request and generated 4 comments.

Comment on lines +36 to +49
const handleSetup = async (type: typeof TETRATE | typeof NANOGPT) => {
setError(null);
setSelectedProvider(type);
try {
const result = type === TETRATE ? await startTetrateSetup() : await startNanogptSetup();
if (result.success) {
onConfigured(type);
} else {
setError({ message: result.message, type });
}
} catch {
setError({ message: 'An unexpected error occurred during setup.', type });
}
};
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The analytics tracking for provider selection is missing for TETRATE and NANOGPT providers. Only LOCAL_PROVIDER calls trackOnboardingProviderSelected. Consider calling this function in the handleSetup function after a successful result to track all provider selections consistently.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Centralise send ing the event for all providers in handleConfigure function

vec![NANOGPT_DEFAULT_MODEL],
NANOGPT_DOC_URL,
vec![ConfigKey::new(NANOGPT_API_KEY, true, true, None, true)],
)
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The NanoGPT provider metadata doesn't include setup_steps, unlike other providers (OpenAI, Anthropic, Google, OpenRouter) that were updated in this PR to include them. Consider adding setup_steps with instructions for obtaining a NanoGPT API key for consistency, or explicitly documenting why it's omitted if the authentication flow is OAuth-based.

Suggested change
)
)
.with_setup_steps(vec![
"Create an account at NanoGPT (https://nano-gpt.com/) and sign in to the dashboard."
.into(),
"From the NanoGPT dashboard, generate an API key with access to the models you want to use."
.into(),
"Configure the generated key as NANOGPT_API_KEY in your goose configuration or environment secrets."
.into(),
])

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can add this later

Comment on lines +2170 to 2171
export type CreateCustomProviderResponse2 = CreateCustomProviderResponses[keyof CreateCustomProviderResponses];

Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type naming collision: CreateCustomProviderResponse is defined both as the schema type at line 130 and as a union type at line 2170 (with CreateCustomProviderResponse2 being the actual union type). This creates confusion. The generated code should use consistent naming to avoid this duplication.

Suggested change
export type CreateCustomProviderResponse2 = CreateCustomProviderResponses[keyof CreateCustomProviderResponses];
export type CreateCustomProviderResponseUnion = CreateCustomProviderResponses[keyof CreateCustomProviderResponses];
/**
* @deprecated Use CreateCustomProviderResponseUnion instead.
*/
export type CreateCustomProviderResponse2 = CreateCustomProviderResponseUnion;

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems fine, the naming method is weird but this is just how the sdk generator works

Comment on lines +96 to +102
const handleCreateCustomProvider = async (data: UpdateCustomProviderRequest) => {
const result = await createCustomProvider({ body: data, throwOnError: true });
setShowCustomModal(false);
if (result.data?.provider_name) {
onConfigured(result.data.provider_name);
}
};
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing error handling for handleCreateCustomProvider. If the createCustomProvider call fails (despite throwOnError: true), the error will be unhandled and could crash the app. The catch block in CustomProviderForm won't handle this since it's called from a different component. Consider wrapping this in a try-catch block to handle API errors gracefully.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the CustomProviderForm to handle the error, no need try catch here

* main: (191 commits)
  fix: add tool_choice and parallel_tool_calls to chatgpt_codex provider (#7867)
  fix: tool confirmation handling for multiple requests (#7856)
  Remove dead OllamaSetup onboarding flow (#7861)
  fix: resolve tokio::sync::Mutex deadlock in recipe retry path (#7832)
  Upgrade Electron 40.6.0 → 41.0.0 (#7851)
  Only show up to 50 lines of source code (#7578)
  fix: stop writing without error when hitting broken pipe for goose session list (#7858)
  feat(acp): add session/set_mode handler (#7801)
  Keep messages in sync (#7850)
  More acp tools (#7843)
  fix: skip upgrade-insecure-requests CSP for external HTTP backends (#7714)
  fix(shell): prevent hang when command backgrounds a child process (#7689)
  Remove include from Cargo.toml in goose-mcp (#7838)
  Exit agent loop when tool call JSON fails to parse (#7840)
  chore: remove redundant husky prepare script (#7829)
  Add github actions workflow for unused deps (#7681)
  fix: prevent SSE connection drops from silently truncating responses (#7831)
  doc: Added notes in contribution guide for pnpm (#7833)
  add prefer-offline to pnpm config to skip unnecessary registry lookups (#7828)
  fix: remove dead read handler from DeveloperClient (#7821)
  ...
* main:
  updated canonical models (#7920)
  feat(autovisualiser): Migrate the autovisualiser extension to MCP Apps  (#7852)
Copy link
Copy Markdown
Collaborator

@jamadeo jamadeo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of nits but this looks nice!

I'm wondering also about the value of the feature flag. Are you thinking that we might want to do a build where we turn this off? Because there is always git revert

"Go to https://console.anthropic.com and sign up or log in",
"Click 'API Keys' in the left sidebar",
"Click 'Create Key'",
"Copy the key and paste it above",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


let is_subscription = Self::check_subscription(&api_key).await;
let host = if is_subscription {
tracing::info!("NanoGPT subscription active, using subscription endpoint");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can probably drop these traces

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to debug

// check so we can track the funnel before the user makes their choice.
let is_onboarding_event =
event_name.starts_with("onboarding_") || event_name == "telemetry_preference_set";
if !is_onboarding_event {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ideally we'd hold onto the event and then send it (or not) only if the user opts in -- think that's possible?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I think we could. I was thinking about this too originally although the code would be a bit complicated. However, we would like to get the metrics for the onboarding as much as we can as requested by UX.

Comment on lines +2170 to 2171
export type CreateCustomProviderResponse2 = CreateCustomProviderResponses[keyof CreateCustomProviderResponses];

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems fine, the naming method is weird but this is just how the sdk generator works

Comment on lines +52 to +75
const load = async () => {
try {
const response = await listLocalModels();
if (response.data) {
setModels(response.data);

const alreadyDownloaded = response.data.find((m) => m.status.state === 'Downloaded');
if (alreadyDownloaded) {
setSelectedModelId(alreadyDownloaded.id);
} else {
const recommended = response.data.find((m: LocalModelResponse) => m.recommended);
if (recommended) setSelectedModelId(recommended.id);
}
}
} catch (error) {
console.error('Failed to load local models:', error);
setErrorMessage('Failed to load available models. Please try again.');
setPhase('error');
return;
}
setPhase('select');
};
load();
}, []);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is still valid?

>
<Key size={20} className="text-text-muted mb-2" />
<span className="font-medium text-text-default text-base block">
Use Your Own Provider
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO the language here could be a little clearer: I don't think of Anthropic/OpenAI as "my own" provider. Maybe something like

| Use a Free/Local Provider                        | Connect to a Provider                                      |
| Use a local model or a service with free credits | Use your own login/key with OpenAI, Anthropic, Google, etc |

<h2 className="text-xl font-light text-text-default mb-1">
{providerName === LOCAL_PROVIDER
? 'Local model ready'
: `Connected to ${providerName}`}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: providerName here seems to be the key, not the "display name" -- when I went through it said Connected to anthropic while I'd expect Anthropic (capital A)

@@ -0,0 +1 @@
export const USE_NEW_ONBOARDING = true;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this here in case we want to do a build where it is disabled?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will be only changed in case the new onboarding flow does not work

@lifeizhou-ap
Copy link
Copy Markdown
Collaborator Author

A couple of nits but this looks nice!

I'm wondering also about the value of the feature flag. Are you thinking that we might want to do a build where we turn this off? Because there is always git revert

Hi @jamadeo,

Thanks for the review!

I added the feature toggle as this PR has lots of changes and also onboarding is a bit critical as this is the first experience after users download the app. In case it went wrong, we can change the feature toggle and launch a patch release. I'll remove it after one release and clean it up

* main:
  Add DCO git commit command to AGENTS.md (#7945)
  fix(claude-code): remove incorrect agent_visible filter on user message (#7931)
  No Check do Check (#7942)
  Log 500 errors and also show error for direct download (#7936)
  fix: retry on authentication failure with credential refresh (#7812)
  Remove java/.ai-usage-marker directory (#7925)
  test(acp): add terminal delegation fixtures and fix shell singleton (#7923)
  fix: bump pctx_code_mode to 0.3.0 for iterator type checking fix (#7892)
  feat: persist GooseMode per-session via session DB (#7854)
  feat(otel): propagate session.id to spans and log records (#7490)
  fix(test): add env_lock to is_openai_reasoning_model tests (#7917)
  fix(acp): pass session_id when loading extensions so skills are discovered (#7868)
@lifeizhou-ap lifeizhou-ap added this pull request to the merge queue Mar 17, 2026
Merged via the queue into main with commit 4604354 Mar 17, 2026
29 of 30 checks passed
@lifeizhou-ap lifeizhou-ap deleted the lifei/simplify_onboarding_flow branch March 17, 2026 01:39
jh-block added a commit that referenced this pull request Mar 17, 2026
* origin/main:
  feat: adversarial agent for preventing leaking of info and more  (#7948)
  Update contributing.md (#7927)
  docs: add credit balance monitoring section (#7952)
  docs: add Cerebras provider to supported providers list (#7953)
  docs: add TUI client documentation to ACP clients guide (#7950)
  fix: removed double dash in pnpm command (#7951)
  docs: polish ACP docs (#7946)
  claude adaptive thinking (#7944)
  feat: new onboarding flow (#7266)
  Add DCO git commit command to AGENTS.md (#7945)
  fix(claude-code): remove incorrect agent_visible filter on user message (#7931)
  No Check do Check (#7942)
  Log 500 errors and also show error for direct download (#7936)
  fix: retry on authentication failure with credential refresh (#7812)
  Remove java/.ai-usage-marker directory (#7925)
  test(acp): add terminal delegation fixtures and fix shell singleton (#7923)
  fix: bump pctx_code_mode to 0.3.0 for iterator type checking fix (#7892)
  feat: persist GooseMode per-session via session DB (#7854)
elijahsgh pushed a commit to elijahsgh/goose that referenced this pull request Mar 21, 2026
elijahsgh pushed a commit to elijahsgh/goose that referenced this pull request Mar 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants