diff --git a/packages/tui/src/component/welcome-panel-utils.ts b/packages/tui/src/component/welcome-panel-utils.ts
new file mode 100644
index 0000000000..853abc2e61
--- /dev/null
+++ b/packages/tui/src/component/welcome-panel-utils.ts
@@ -0,0 +1,46 @@
+// Pure breakpoint logic for WelcomePanel, split out (like upgrade-indicator-utils)
+// so it's unit-testable without the component's render/context dependencies.
+//
+// The full two-column boot box (block wordmark + description) is a ~13-row
+// bordered box, so on a typical terminal it eats ~40% of the screen with no way
+// to shrink it (issue #1067). We scale it down by the space the panel ACTUALLY
+// has on both axes:
+// - width: the terminal minus the caller's padding and any sibling sidebar.
+// - height: the terminal minus the fixed chrome that always shares the column
+// with the panel (top spacer + prompt + footer), so a big panel is
+// chosen only when it won't crowd the prompt off a short terminal.
+// `medium` (no wordmark) is the common case; `full` only when there's real room.
+//
+// Naming: these are the MINIMUMS a tier requires, matched with strict `<`
+// (`width < FULL_MIN_WIDTH` → not full). MEDIUM_MIN_* is the floor for medium
+// (below → compact); FULL_MIN_* is the floor for full (below → medium). All in
+// terms of AVAILABLE (usable) size, not the raw terminal.
+
+export type WelcomePanelVariant = "full" | "medium" | "compact"
+
+/**
+ * Rows the panel must leave for the always-present chrome below/around it (the
+ * prompt, the footer, and the home top spacer). Callers subtract this from the
+ * terminal height to get the panel's usable height. An estimate — the prompt can
+ * grow with multi-line input, but at rest this is the fixed cost.
+ */
+export const PANEL_VERTICAL_RESERVE = 8
+
+/** Minimum usable size for the medium panel; below either → compact (one line). */
+export const MEDIUM_MIN_WIDTH = 60
+export const MEDIUM_MIN_HEIGHT = 16
+/** Minimum usable size for the full wordmark panel; below either → medium. */
+export const FULL_MIN_WIDTH = 110
+export const FULL_MIN_HEIGHT = 36
+
+/**
+ * Choose the WelcomePanel layout from the panel's AVAILABLE size — width already
+ * minus padding/sidebar, height already minus PANEL_VERTICAL_RESERVE. Not the
+ * raw terminal (that's the #1067 bug: a sidebar-narrowed column, or a short
+ * terminal, would still pick `full`).
+ */
+export function welcomePanelVariant(width: number, height: number): WelcomePanelVariant {
+ if (width < MEDIUM_MIN_WIDTH || height < MEDIUM_MIN_HEIGHT) return "compact"
+ if (width < FULL_MIN_WIDTH || height < FULL_MIN_HEIGHT) return "medium"
+ return "full"
+}
diff --git a/packages/tui/src/component/welcome-panel.tsx b/packages/tui/src/component/welcome-panel.tsx
index b9ea310bfd..b8c16eff9c 100644
--- a/packages/tui/src/component/welcome-panel.tsx
+++ b/packages/tui/src/component/welcome-panel.tsx
@@ -1,78 +1,139 @@
-import { Show } from "solid-js"
+import { Match, Show, Switch, createMemo } from "solid-js"
import { TextAttributes } from "@opentui/core"
+import { useTerminalDimensions } from "@opentui/solid"
import { useTheme } from "../context/theme"
import { Logo } from "./logo"
import { InstallationVersion } from "@opencode-ai/core/installation/version"
import { useReady } from "./altimate-onboarding"
+import { welcomePanelVariant } from "./welcome-panel-utils"
-// altimate_change — Claude-Code-style full-width boot box: big block wordmark on
-// the left and a single "What is Altimate Code" section on the right. Shared
-// between the home route and the session view so the header stays consistent
-// when a command (e.g. /discover) starts a session. zIndex keeps it above
-// transient top toasts (update/MCP) that would otherwise blank its top rows.
-export function WelcomePanel() {
+const CONNECT_CTA = "Connect your AI model to start."
+
+// altimate_change — Claude-Code-style boot box: "What is Altimate Code" plus the
+// readiness-aware CTA. Shared between the home route and the session view so the
+// header stays consistent when a command (e.g. /discover) starts a session.
+// zIndex keeps it above transient top toasts (update/MCP) that would otherwise
+// blank its top rows.
+//
+// Responsive (issue #1067): the full two-column boot box is a ~13-row bordered
+// box that ate ~40% of the screen. It now scales down by AVAILABLE size,
+// following the repo's breakpoint idiom (createMemo over useTerminalDimensions,
+// cf. routes/session/permission.tsx:450, component/upgrade-indicator.tsx:14):
+// full — wordmark + full description (large windows only)
+// medium — title + one condensed line, no wordmark (the common case)
+// compact — a short line; the border title already carries the version
+//
+// `availableWidth` / `availableHeight` are the space the panel actually gets, not
+// the whole terminal — the caller subtracts its padding, any sibling sidebar
+// (session's contentWidth), and the fixed prompt/footer chrome
+// (PANEL_VERTICAL_RESERVE). Using the raw terminal would keep `full` selected in
+// a sidebar-narrowed column or a short window and swell the panel back up — the
+// bug #1067 is about. Both fall back to the terminal dimension when omitted.
+export function WelcomePanel(props: { availableWidth?: number; availableHeight?: number }) {
const { theme } = useTheme()
const ready = useReady()
+ const dimensions = useTerminalDimensions()
+
+ const variant = createMemo(() =>
+ welcomePanelVariant(props.availableWidth ?? dimensions().width, props.availableHeight ?? dimensions().height),
+ )
+
+ const title = InstallationVersion === "local" ? " Altimate Code " : ` Altimate Code v${InstallationVersion} `
+
return (
- {/* left column — the block-letter wordmark (59 cols wide) */}
-
-
- Welcome to Altimate Code
-
-
-
- {/* right column — tips + what-is sections */}
-
-
-
- What is Altimate Code
-
-
- Altimate Code is a specialized data engineering harness that sits between any LLM and your entire data
- stack.
-
-
- It gives your AI real context — column-level lineage, SQL analysis, dbt, and live warehouse metadata — so it
- reasons about your data instead of guessing.
-
- {/* CTA only until a model is connected — stale afterwards */}
-
-
- Connect your AI model to start.
+
+ {/* compact — a short line; the border title already carries the version.
+ wrapMode keeps it readable if the terminal is extremely narrow. */}
+
+
+
+ {ready() ? "Your data-aware AI harness." : CONNECT_CTA}
-
-
-
+
+
+
+ {/* medium — title + one condensed description + CTA, no block wordmark */}
+
+
+
+ Welcome to Altimate Code
+
+
+ Gives your AI real context on your data stack — lineage, SQL, dbt, and live warehouse metadata.
+
+
+
+ {CONNECT_CTA}
+
+
+
+
+
+ {/* full — the original two-column boot box */}
+
+
+ {/* left column — the block-letter wordmark (logo is ~50 cols) */}
+
+
+ Welcome to Altimate Code
+
+
+
+ {/* right column — what-is section */}
+
+
+
+ What is Altimate Code
+
+
+ Altimate Code is a specialized data engineering harness that sits between any LLM and your entire data
+ stack.
+
+
+ It gives your AI real context — column-level lineage, SQL analysis, dbt, and live warehouse metadata —
+ so it reasons about your data instead of guessing.
+
+ {/* CTA only until a model is connected — stale afterwards */}
+
+
+ {CONNECT_CTA}
+
+
+
+
+
+
+
)
}
diff --git a/packages/tui/src/routes/home.tsx b/packages/tui/src/routes/home.tsx
index d0926bec82..caa6d10e88 100644
--- a/packages/tui/src/routes/home.tsx
+++ b/packages/tui/src/routes/home.tsx
@@ -19,6 +19,7 @@ import { useTheme } from "../context/theme"
// one-line "Get started: /connect ... /discover ..." hint below, which duplicated the
// same guidance the panel's "Tips for getting started" section now covers.
import { WelcomePanel } from "../component/welcome-panel"
+import { PANEL_VERTICAL_RESERVE } from "../component/welcome-panel-utils"
// altimate_change end
let once = false
@@ -108,7 +109,13 @@ export function Home() {
-
+ {/* Size to the panel's real space, not the whole terminal (#1067):
+ -4 for this column's paddingLeft/Right; -PANEL_VERTICAL_RESERVE for
+ the top spacer + prompt + footer that share the height. */}
+
diff --git a/packages/tui/src/routes/session/index.tsx b/packages/tui/src/routes/session/index.tsx
index a00e321070..0521a6248c 100644
--- a/packages/tui/src/routes/session/index.tsx
+++ b/packages/tui/src/routes/session/index.tsx
@@ -26,6 +26,7 @@ import { useTuiPaths, useTuiTerminalEnvironment } from "../../context/runtime"
import { Spinner } from "../../component/spinner"
// altimate_change — shared boot box at the top of the session scrollback
import { WelcomePanel } from "../../component/welcome-panel"
+import { PANEL_VERTICAL_RESERVE } from "../../component/welcome-panel-utils"
import { createSyntaxStyleMemo, generateSubtleSyntax, selectedForeground, useTheme } from "../../context/theme"
import { BoxRenderable, ScrollBoxRenderable, addDefaultParsers, TextAttributes, RGBA } from "@opentui/core"
import { Prompt, type PromptRef } from "../../component/prompt"
@@ -1186,7 +1187,13 @@ export function Session() {
/discover) starts a session. Outside the scrollbox: the bordered panel
does not paint reliably inside the scroll viewport. */}
-
+ {/* Size to the panel's real space, not the terminal (#1067):
+ contentWidth already subtracts the sidebar + padding;
+ -PANEL_VERTICAL_RESERVE leaves room for the prompt + footer. */}
+
{/* altimate_change end */}
{
+ expect(welcomePanelVariant(WIDE, TALL)).toBe("full")
+ expect(welcomePanelVariant(FULL_MIN_WIDTH, FULL_MIN_HEIGHT)).toBe("full") // exactly at the floor
+})
+
+test("full's width gate is real — width one below the floor drops to medium even when tall", () => {
+ expect(welcomePanelVariant(FULL_MIN_WIDTH - 1, TALL)).toBe("medium")
+})
+
+test("full's height gate is real — height one below the floor drops to medium even when wide", () => {
+ expect(welcomePanelVariant(WIDE, FULL_MIN_HEIGHT - 1)).toBe("medium")
+})
+
+test("compact's width gate is real — width one below the medium floor is compact even when tall", () => {
+ expect(welcomePanelVariant(MEDIUM_MIN_WIDTH - 1, TALL)).toBe("compact")
+})
+
+test("compact's height gate is real — height one below the medium floor is compact even when wide", () => {
+ expect(welcomePanelVariant(WIDE, MEDIUM_MIN_HEIGHT - 1)).toBe("compact")
+})
+
+test("compact→medium boundary is exact (at the floor is medium)", () => {
+ expect(welcomePanelVariant(MEDIUM_MIN_WIDTH, MEDIUM_MIN_HEIGHT)).toBe("medium")
+ expect(welcomePanelVariant(MEDIUM_MIN_WIDTH, TALL)).toBe("medium")
+ expect(welcomePanelVariant(WIDE, MEDIUM_MIN_HEIGHT)).toBe("medium")
+})
+
+test("everyday terminals get medium, not the oversized wordmark", () => {
+ // Inputs are AVAILABLE size (terminal minus padding/sidebar on width, minus
+ // PANEL_VERTICAL_RESERVE on height). A 106x31 terminal → ~(102, 23):
+ expect(welcomePanelVariant(102, 23)).toBe("medium")
+ // 80x24 terminal → ~(76, 16) — medium exactly at the height floor:
+ expect(welcomePanelVariant(76, 16)).toBe("medium")
+ // #1067 session case: a 130-col terminal with the 42-col sidebar leaves ~84
+ // usable cols → medium (was wrongly full when it used the whole terminal width).
+ expect(welcomePanelVariant(130 - 42 - 4, 50 - PANEL_VERTICAL_RESERVE)).toBe("medium")
+})
+
+test("a short terminal drops to compact once prompt/footer chrome is reserved (#1067 height)", () => {
+ // 120x22: wide, but only ~14 usable rows after the ~8-row chrome → compact,
+ // where the raw terminal height (22) would have picked medium.
+ expect(welcomePanelVariant(120 - 4, 22 - PANEL_VERTICAL_RESERVE)).toBe("compact")
+})
+
+test("degenerate sizes collapse to compact", () => {
+ expect(welcomePanelVariant(0, 0)).toBe("compact")
+ expect(welcomePanelVariant(1, 1)).toBe("compact")
+})