Skip to content
42 changes: 42 additions & 0 deletions docs/design/simplify-nav-new-users/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Simplify navigation for new signup users

**Status:** Planning complete — decisions locked, ready to implement
**Date:** 2026-07-24

New signup users land on the full platform sidebar, which is noise when their only goal is
building an agent. This workspace plans a nav-only simplification in two phases. **Phase 1**
hides the advanced pages (Prompts, the Evaluation group, Overview, Registry, Evaluations) for
new signups. **Phase 2** adds a per-user **"Simplified navigation"** toggle in Settings →
Account so anyone can switch back to the full view to use the LLM-app pages. Existing and
returning users default to the full view throughout.

## Decisions

- Two phases: Phase 1 = hide-for-new-signups; Phase 2 = the Settings → Account toggle
(additive — touches no Phase-1 file except one derived atom).
- Nav-only — hide sidebar entries; no route guards, no in-app link changes.
- Hide when simplified: Prompts, Evaluation group (project); Overview, Registry, Evaluations (app).
- Keep always: Home, Agents, Observability, app Playground.
- Default mode seeded by a fresh forward-only key `navSimplifiedDefaultAtom`, written at signup
(new signups → simplified); everyone else → full. Deliberately **not** `isNewUserAtom`, which
is sticky-true for existing users and would strip their advanced nav.
- Stable seam: the sidebar reads one derived atom `advancedNavHiddenAtom` (in `state/onboarding`
selectors) — Phase 1 `= navSimplifiedDefault`, Phase 2 `= override ?? navSimplifiedDefault`.
- No backend, no team-wide enforcement — per-user preference; an invited teammate flips the
Phase-2 switch to match their team. A workspace-level flag is deferred, not blocked.
- Built on the sidebar's existing `isHidden` mechanism; one OSS sidebar file, both editions inherit it.

## Deliverables

- [context.md](./context.md) — problem, phased scope, out-of-scope, product language, success criteria.
- [research.md](./research.md) — how the sidebar, new-user state, and settings tabs work today, with `file:line`.
- [plan.md](./plan.md) — the phased, sliced implementation plan (Phase 1: Slice 0–4; Phase 2: Slice 5–6).
- [status.md](./status.md) — locked decisions, open questions, next action.

## Intended outcome

A user who has just signed up sees a focused, agent-first sidebar: Home, Agents, and
Observability at the project level, Playground + Observability inside an app. Anyone who wants
the complete platform — an existing LLM-app team, or an invited teammate — flips one switch in
Settings → Account and gets it back, with the choice remembered. No one is ever stuck in the
wrong view.
90 changes: 90 additions & 0 deletions docs/design/simplify-nav-new-users/context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Context — Simplify navigation for new signup users

## Problem

The sidebar exposes the full platform to everyone the moment they sign up. For a brand-new
user whose only goal is building an agent, that surface is noise: Prompts, the whole
Evaluation group, Registry, Evaluations, and the app Overview are pages the agent flow does
not need yet. They add cognitive load and lead to dead-end or empty pages during the first
session.

The product has pivoted to agent building (see `docs/design/onboarding-revamp/HANDOFF.md`).
The navigation should match that focus for people arriving new — while still letting anyone
who needs the full platform switch to it.

## Scope

Nav-only. The entries disappear from the sidebar; nothing else changes. Delivered in two
phases.

**Advanced items hidden when the simplified view is active:**

Project scope (`projectItems` in `useSidebarConfig`):
- Prompts
- Evaluation — the entire group (Test sets, Evaluators, Evaluation runs, Annotation Queues)

App scope (`appItems` in `useSidebarConfig`):
- Overview
- Registry
- Evaluations

Everything else always stays: Home, Agents, project Observability; app Playground and app
Observability.

### Phase 1 (this delivery) — hide for new signups

New signup users get the simplified sidebar, flagged by a fresh forward-only key
(`navSimplifiedDefaultAtom`, `agenta:onboarding:<userId>:nav-simplified`) seeded at signup.
Everyone else is unaffected — existing users never have the key, so they keep the full nav. We
do not reuse `isNewUserAtom` (sticky-true for everyone who ever signed up; reusing it would
break current users). There is no switch yet, so a genuinely-new solo user stays simplified
until Phase 2 ships. Invited teammates are never flagged (see research.md §7), so they keep the
full nav.

### Phase 2 (follow-up) — the toggle

A "Simplified navigation" switch in **Settings → Account**, backed by a per-user localStorage
override. It flips the mode either way: a new user can reveal everything (e.g. to use the
LLM-app pages), and an existing user or invited teammate can opt into the focused view. Phase 2
is additive — it changes no Phase-1 file except the one derived atom.

## Out of scope (both phases)

- **Route guards.** Direct URLs (`/prompts`, `/evaluations`, `/apps/[id]/overview`,
`/apps/[id]/variants`, `/apps/[id]/evaluations`) still resolve. We only remove the nav
entry points.
- **In-app links.** Buttons or cards elsewhere that navigate to a hidden page keep working.
- **Team-wide enforcement.** The preference is per-user, not per-workspace. An agent team's
invited teammate defaults to the full view and (in Phase 2) flips the switch to match the
team; we do not force every member to the same mode. A workspace-level flag would do that,
but it needs a backend field and is deferred. The override model does not block adding it.
- **A backend field.** No server change in either phase. Everything is client-side localStorage.

## Product language

- **New signup user** — a user who signs up after this ships, flagged by the fresh
`navSimplifiedDefaultAtom` key (`agenta:onboarding:<userId>:nav-simplified`), seeded `true` at
signup alongside `setIsNewUser(true)`. Distinct from `isNewUserAtom`, which is sticky-true for
existing users and is deliberately not reused.
- **Simplified navigation** — the reduced, agent-focused sidebar (advanced items hidden).
- **Full navigation** — the complete sidebar (today's behavior).
- **Simplified-nav preference** — the per-user override (`simplifiedNavOverrideAtom`, Phase 2):
`null` = follow the default, `true` = force simplified, `false` = force full.
- **Effective mode** — `override ?? navSimplifiedDefault`, exposed as `advancedNavHiddenAtom`
(in `state/onboarding` selectors). This single value drives both the sidebar and the switch.

## Success criteria

**Phase 1**
1. A new signup user sees the simplified sidebar (no Prompts, Evaluation group, Overview,
Registry, or Evaluations).
2. An existing/returning user sees the full sidebar exactly as before.
3. Both editions (OSS and EE) get the behavior from one sidebar change — no EE fork.
4. Hidden items never render, auto-open, or become the selected key while simplified.
5. No backend change is introduced.

**Phase 2**
6. The Settings → Account switch flips the effective mode in either direction and survives a
reload.
7. Toggling the switch updates the sidebar without a full page reload.
8. Phase 1's sidebar behavior is unchanged when no override is set.
202 changes: 202 additions & 0 deletions docs/design/simplify-nav-new-users/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
# Plan — Simplify nav for new signup users

Two phases. **Phase 1** ships the hide-for-new-signups behavior. **Phase 2** adds the
Settings → Account toggle so users can switch back to the full view (e.g. to use the LLM-app
pages). Phase 2 is designed to be **purely additive** — it touches no Phase-1 file except the
one derived atom.

## Scope

- Nav-only. No route guards, no in-app link changes. No backend. No team-wide enforcement.
- **Phase 1:** new signups (flagged by the fresh `nav-simplified` key) get the simplified
sidebar; everyone else — including all existing users — is unaffected. No way to switch yet, so
a genuinely-new solo user stays simplified until Phase 2. (Invited teammates are never flagged,
so they keep the full nav — see research.md §7.)
- **Phase 2:** a per-user localStorage override + a switch in Settings → Account, so anyone can
force simplified or full.

## The stable seam

One derived atom is the sole nav-simplify dependency the sidebar reads, so the sidebar edits are
written once (Phase 1) and never touched again. It lives in `state/onboarding/selectors.ts`
alongside the other onboarding-driven nav gates (`deadEndNavDisabledAtom`, `homeNavInertAtom`):

- **Phase 1:** `advancedNavHiddenAtom = navSimplifiedDefault` (thin passthrough over a fresh,
forward-only per-user key).
- **Phase 2:** `advancedNavHiddenAtom = override ?? navSimplifiedDefault` (add the override; same
name, same consumers).

**Why not reuse `isNewUserAtom`:** it is sticky-true for everyone who ever signed up (including
existing users), so deriving from it would strip the advanced nav from current users. Phase 1
instead introduces a new per-user key `agenta:onboarding:<userId>:nav-simplified`
(`navSimplifiedDefaultAtom`, default `false`) written only on signups going forward.

The sidebar reads `advancedNavHiddenAtom` with a bare `useAtomValue` (matching its sibling nav
gates); only the atom's body changes between phases.

---

# Phase 1 — Hide advanced nav for new signups

## Slice 0 — Pin the current sidebar with a test

1. Unit test over `useSidebarConfig` output (or `filterVisibleItems` on the built items)
asserting the five target keys are **present** when `isNavSimplified === false`.
2. Assert non-targets (Home, Agents, Observability, app Playground) are present in both modes.

**Exit:** a passing test capturing the pre-change sidebar (targets + non-targets visible).

## Slice 1 — The forward-only default + the derived seam atom

1. Add the durable per-user default in `web/oss/src/lib/onboarding/atoms.ts` (reuses the
existing per-user scoping infra — `onboardingStorageUserIdAtom`, `createScopedStorageKey`):

```ts
const navSimplifiedDefaultAtomFamily = atomFamily((userId: string) =>
atomWithStorage<boolean>(createScopedStorageKey(userId, "nav-simplified"), false),
)

export const navSimplifiedDefaultAtom = atom(
(get) => {
const userId = get(onboardingStorageUserIdAtom)
return userId ? get(navSimplifiedDefaultAtomFamily(userId)) : false
},
(get, set, next: boolean) => {
const userId = get(onboardingStorageUserIdAtom)
if (userId) set(navSimplifiedDefaultAtomFamily(userId), next)
},
)
```

Export it from the `lib/onboarding` barrel.

2. Seed it at signup in `web/oss/src/hooks/usePostAuthRedirect.ts`: call
`setNavSimplifiedDefault(true)` next to each `setIsNewUser(true)` (EE and OSS non-invited
branches). Invited users `return` before this, so they stay on full nav.

3. Add the derived seam atom to `web/oss/src/state/onboarding/selectors.ts`, next to
`deadEndNavDisabledAtom` (imports `navSimplifiedDefaultAtom` from `@/oss/lib/onboarding/atoms`):

```ts
// Phase 1: follows the signup-era default. Phase 2 adds a user override here.
export const advancedNavHiddenAtom = atom((get) => get(navSimplifiedDefaultAtom))
```

No new module or wrapper hook — consumers read it with a bare `useAtomValue`, like the
sibling nav gates.

**Exit:** `advancedNavHiddenAtom` returns the new per-user default (not `isNewUser`); a signup
sets `nav-simplified` true; both editions compile.

## Slice 2 — Hide the two project-scope items

Edit `web/oss/src/components/Sidebar/hooks/useSidebarConfig/index.tsx`.

1. `const hideAdvancedNav = useAtomValue(advancedNavHiddenAtom)` near the top (import the atom
from the existing `@/oss/state/onboarding` barrel).
2. Prompts (`PROMPTS_SIDEBAR_KEY`, `:72`): add `isHidden: hideAdvancedNav`.
3. Evaluation group (`evaluation-group`, `:88`): add `isHidden: hideAdvancedNav`.
4. Add `hideAdvancedNav` to the `projectItems` `useMemo` deps.

**Exit:** with the simplified default true, `projectItems` (post `filterVisibleItems`) has no
Prompts and no `evaluation-group`; with it false, both present. Non-targets unchanged.

## Slice 3 — Hide the three app-scope items

Same file, `appItems` memo (`:144`).

1. Overview (`:147`), Registry (`:164`), Evaluations (`:174`): change `isHidden: isHidden` to
`isHidden: isHidden || hideAdvancedNav`. Do **not** touch Playground or app Observability.
2. Add `hideAdvancedNav` to the `appItems` `useMemo` deps.

**Exit:** with the simplified default true, `appItems` (post `filterVisibleItems`) has no
Overview, Registry, or Evaluations, and still has Playground + Observability when the app-context
gate allows. With it false, all five behave exactly as before.

## Slice 4 — Manual QA (Phase 1)

1. Run the local stack (OSS + dev per root `AGENTS.md`).
2. New user: set `agenta:onboarding:active-user-id` to the user id and
`agenta:onboarding:<id>:nav-simplified` to `true`, reload → simplified sidebar. Confirm the
five items gone, Home/Agents/Observability/Playground remain.
3. Set `nav-simplified` to `false` (or remove the key), reload → full sidebar returns.
4. Check both the main (project) and workflow (app) sidebars.
5. Confirm no empty section header / stray divider where the Evaluation group was
(`filterVisibleSections` drops empty sections — verify visually).

**Exit:** both states verified in the running app; `pnpm lint-fix` clean. **Phase 1 shippable.**

---

# Phase 2 — Settings → Account toggle (follow-up)

Additive. Nothing from Phase 1 changes except the body of `advancedNavHiddenAtom`.

## Slice 5 — The override state

Add the override atom (near `navSimplifiedDefaultAtom`) and extend `advancedNavHiddenAtom` in
`web/oss/src/state/onboarding/selectors.ts`:

```ts
import {atomWithStorage} from "jotai/utils"

/** null = follow default, true = force simplified, false = force full. Per-user via LS. */
export const simplifiedNavOverrideAtom = atomWithStorage<boolean | null>(
"agenta:nav:simplified-override",
null,
)

// Phase 2: explicit choice wins; else fall back to the signup-era default.
export const advancedNavHiddenAtom = atom((get) => {
const override = get(simplifiedNavOverrideAtom)
return override ?? get(navSimplifiedDefaultAtom)
})
```

Unit test: override `null` → `navSimplifiedDefault`; override `true`/`false` → that value.

**Exit:** derived atom follows the table in `context.md`, proven by the test. Sidebar behavior
from Phase 1 is unchanged when no override is set.

## Slice 6 — The switch

1. Add `web/oss/src/components/pages/settings/Account/NavigationPreference.tsx`: an antd `Switch`
labeled "Simplified navigation" with a one-line description ("Hide advanced features —
Prompts, Evaluations, Registry — for a focused agent workspace"). `checked` reads
`advancedNavHiddenAtom`; `onChange` writes the boolean to `simplifiedNavOverrideAtom`.
2. Render it in the Account tab, above `DeleteAccount`, at
`pages/w/[workspace_id]/p/[project_id]/settings/index.tsx:171` (`case "account"`).

**Exit:** toggling shows/hides the advanced items live (no reload); the choice survives a
reload; both directions verified. Non-new users can now opt into simplified, and new users can
reveal everything.

---

## Files touched

**Phase 1**
- `web/oss/src/lib/onboarding/atoms.ts` — new `navSimplifiedDefaultAtom` + family + storage key.
- `web/oss/src/lib/onboarding/index.ts` — export `navSimplifiedDefaultAtom` from the barrel.
- `web/oss/src/hooks/usePostAuthRedirect.ts` — seed the default at signup (two call sites).
- `web/oss/src/state/onboarding/selectors.ts` — new `advancedNavHiddenAtom` (passthrough seam),
next to `deadEndNavDisabledAtom`.
- `web/oss/src/components/Sidebar/hooks/useSidebarConfig/index.tsx` — five `isHidden` edits +
`useAtomValue(advancedNavHiddenAtom)` + two dep-array entries.

**Phase 2**
- `web/oss/src/state/onboarding/selectors.ts` — add `simplifiedNavOverrideAtom`, extend
`advancedNavHiddenAtom`.
- `web/oss/src/components/pages/settings/Account/NavigationPreference.tsx` — new switch.
- `web/oss/src/pages/w/[workspace_id]/p/[project_id]/settings/index.tsx` — render the switch in
the `account` case.

No changes to `engine/` or `scopes/`, or any EE file, in either phase.

## Rollback

Phase 1: revert `advancedNavHiddenAtom`, `navSimplifiedDefaultAtom` + signup seed, the sidebar
`useAtomValue` read, and the five `isHidden` edits — pure code revert, no data migration, no
server state. The harmless `agenta:onboarding:<userId>:nav-simplified` localStorage key can be
left. Phase 2: delete the switch + settings render and revert `advancedNavHiddenAtom` to the
passthrough; the harmless `agenta:nav:simplified-override` localStorage key can be left.
Loading
Loading