Help us shape the future of Go! Take the 2026 Go Developer Survey

app

package
v1.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 27, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package app is the core of the native desktop UI: the app-wide Context handed to every view, the registry of areas (chat, settings, files, ...), the router and the window layout (sidebar, header, content). Each area lives in its own package under internal/nativeui/app/<area> and registers itself from init(); see internal/nativeui/README.md for the conventions.

Index

Constants

View Source
const DefaultPath = "/chat"

DefaultPath is the route shown at start-up.

View Source
const DocsURL = "https://madeindigio.github.io/pando-docs/"

DocsURL is the documentation site the header links to.

Variables

View Source
var CustomFrame = shell.CustomFrame

CustomFrame reports whether the UI draws its own title bar and window buttons (no native ones): Linux and Windows, never macOS. A variable so tests can switch the platform.

View Source
var OpenExternal = func(url string) { _ = mygo.Shell.OpenExternal(url) }

OpenExternal opens a URL in the default browser (a variable for tests).

Functions

func OnStart

func OnStart(fn func(a *Context))

OnStart registers fn to run once, on the UI thread, in the first frame of the root view (after the dispatcher is connected). Areas use it to react to the server state at start-up, e.g. the setup area opens its assistant when the server says the first-run setup is needed. fn must not block: start goroutines with a.Go and come back through a.Update.

func ParseThemeID

func ParseThemeID(id string) (kit.Family, kit.Mode, bool)

ParseThemeID parses a backend theme id ("family-mode", the config field shared with the TUI). ok is false for ids the desktop does not know (TUI-only themes such as "pando-nobg").

func Register

func Register(ar Area)

Register adds an area, replacing one with the same ID (so a real area replaces its placeholder regardless of init order: a non-placeholder registration always wins over a placeholder).

func RegisterBanner

func RegisterBanner(order int, f func(a *Context) Banner)

RegisterBanner registers a banner factory; banners stack by order.

func RegisterCommand

func RegisterCommand(cmd Command)

RegisterCommand adds a quick menu command, replacing one with the same ID.

func RegisterHeaderSlot

func RegisterHeaderSlot(s HeaderSlot)

RegisterHeaderSlot adds a header control, replacing one with the same ID.

func RegisterOverlay

func RegisterOverlay(f func(a *Context) Overlay)

RegisterOverlay registers a factory called once per window root.

func RegisterShellExt

func RegisterShellExt(f func(a *Context) ShellExt)

RegisterShellExt registers a factory called by NewRoot.

func RegisterStatusItem

func RegisterStatusItem(it StatusItem)

RegisterStatusItem adds a status strip item (call from init). The extensions package registers the "status-bar" slot here.

func ShortenPath

func ShortenPath(p string) string

ShortenPath replaces the home directory with ~ (the Web UI's shortenPath), also for paths under another home (remote instances).

Types

type Area

type Area struct {
	// ID is unique and stable ("chat", "settings").
	ID string
	// Path is where the sidebar entry navigates ("/chat").
	Path string
	// Patterns are the router patterns the area builds; Path when empty.
	// Use "/settings/{section...}" style patterns for sub-pages.
	Patterns []string
	// TitleKey is the i18n key of the label and header title ("nav.chat").
	TitleKey string
	// Icon is a kit icon name.
	Icon    string
	Section Section
	// Order sorts entries within a section (ascending).
	Order int
	// New builds the area's view once, the first time it is shown; the view
	// then keeps its state across navigation.
	New func(a *Context) View
	// Placeholder marks areas not built yet.
	Placeholder bool
	// Visible, when set, decides on each frame whether the sidebar shows
	// the entry (the extensions area hides itself on builds without panels).
	// The area stays routable either way.
	Visible func(a *Context) bool
}

Area is a top-level destination of the app (a sidebar entry and its routes).

func Areas

func Areas() []Area

Areas returns the registered areas sorted by section then order.

func Lookup

func Lookup(id string) (Area, bool)

Lookup returns the area with id.

type Banner = Overlay

Banner is a strip drawn above the header of the main tab (config init, update notice). Build runs every frame and draws nothing when not needed.

type Batch

type Batch[T any] struct {
	// contains filtered or unexported fields
}

Batch coalesces items pushed from goroutines into one UI update per frame: Push queues an item and schedules a single Update that hands every item queued meanwhile to apply. It is how streams feed the UI without one frame per token.

func NewBatch

func NewBatch[T any](update func(func()), apply func([]T)) *Batch[T]

NewBatch returns a batch applying items on the UI thread through update (usually Context.Update).

func (*Batch[T]) Push

func (b *Batch[T]) Push(v T)

Push queues an item. Safe from any goroutine.

type Closer

type Closer interface {
	Close()
}

Closer is implemented by views that own goroutines or streams to stop when the app shuts down.

type Command

type Command struct {
	ID    string
	Title string
	// TitleKey, when set, is the i18n key of the title (Title is then the
	// fallback when the key is missing).
	TitleKey    string
	Description string
	// Group is "command" (default) or "account".
	Group    string
	Icon     string
	Keywords []string
	Run      func(a *Context)
}

Command is an entry of the quick menu (command palette).

func Commands

func Commands() []Command

Commands returns the registered quick menu commands.

type Context

type Context struct {
	// Ctx is canceled when the app shuts down: derive goroutine contexts
	// from it.
	Ctx context.Context
	// Client talks to the Pando server.
	Client *client.Client
	// Server describes the server (version, startup mode).
	Server client.ServerInfo
	// CWD is the working directory of the server, when known.
	CWD string
	// Router navigates between areas (paths of the registered areas).
	Router *ui.Router
	// Toasts queues toasts from any goroutine.
	Toasts *kit.Toaster
	// Theme selects family, mode and accent; read every frame.
	Theme kit.Settings
	// Log is the UI logger.
	Log *slog.Logger
	// contains filtered or unexported fields
}

Context is the app-wide context every view receives. Its fields are set once at start-up; mutate view state only on the UI thread (in the view, or through Update from goroutines).

func NewContext

func NewContext(ctx context.Context, c *client.Client) *Context

NewContext returns a context with defaults for what opts leaves empty.

func (*Context) ActiveSessionID

func (a *Context) ActiveSessionID() string

ActiveSessionID returns the chat session the route shows ("" outside a session), from /chat/s/{id} or /chat/simple/s/{id}.

func (*Context) ApplyPrefs

func (a *Context) ApplyPrefs(p client.UIPrefs)

ApplyPrefs applies persisted UI preferences (theme, language, sidebar) to the live state. UI thread.

func (*Context) CycleThemeMode

func (a *Context) CycleThemeMode()

CycleThemeMode cycles system -> light -> dark and persists it.

func (*Context) FocusProjectWorkspace

func (a *Context) FocusProjectWorkspace(id string)

FocusProjectWorkspace focuses a project workspace tab (tray menu).

func (*Context) ForClient

func (a *Context) ForClient(c *client.Client, cwd string) *Context

ForClient returns a context that talks to another server (a project's child instance through the parent proxy, see client.Client.Derive) while sharing everything else: the window dispatcher, toasts, ctx and logger. Areas are instantiated against it with Area.New(child), which is how a project workspace hosts chat, files, ... for another project. The child has its own Router (the routes of the embedded areas must not move the main window) and its own Server info and CWD. Its Theme is not used: the root view applies the theme once per frame and kit.Current() is global.

func (*Context) Go

func (a *Context) Go(fn func(ctx context.Context))

Go runs fn on a goroutine with the app context, logging a panic instead of crashing the UI.

func (*Context) InsertIntoChatDraft

func (a *Context) InsertIntoChatDraft(text string)

InsertIntoChatDraft appends text to the pending chat draft.

func (*Context) Invalidate

func (a *Context) Invalidate()

Invalidate asks for a redraw.

func (*Context) IsChild

func (a *Context) IsChild() bool

IsChild reports whether the context is a project workspace's (made by ForClient): its areas are embedded in a tab, without the window header.

func (*Context) Navigate

func (a *Context) Navigate(path string)

Navigate pushes a path on the router (UI thread).

func (*Context) OpenModelSwitcher

func (a *Context) OpenModelSwitcher()

OpenModelSwitcher opens the model switcher overlay.

func (*Context) OpenQuickMenu

func (a *Context) OpenQuickMenu()

OpenQuickMenu opens the command palette.

func (*Context) PeekChatDraft

func (a *Context) PeekChatDraft() string

PeekChatDraft returns the pending chat draft without clearing it.

func (*Context) ReportError

func (a *Context) ReportError(title string, err error)

ReportError tells the user a background call failed. Authorization failures get a clear message of their own, shown at most once a minute.

func (*Context) SavePrefs

func (a *Context) SavePrefs(patch client.UIPrefs)

SavePrefs persists a preferences patch in the background (the server merges it). A failure is logged, and a 401 is surfaced.

func (*Context) SetDispatcher

func (a *Context) SetDispatcher(d Dispatcher)

SetDispatcher connects the context to its window. Until then Update runs nothing (there is no UI to update) and Invalidate is a no-op.

func (*Context) SetLanguage

func (a *Context) SetLanguage(lang string)

SetLanguage selects and persists the UI language. UI thread.

func (*Context) SetSidebarCollapsed

func (a *Context) SetSidebarCollapsed(v bool)

SetSidebarCollapsed collapses or expands the sidebar and persists it.

func (*Context) SetTheme

func (a *Context) SetTheme(s kit.Settings)

SetTheme selects and persists the theme. UI thread.

func (*Context) Shell

func (a *Context) Shell() *Shell

Shell returns the shared window state of the root context (a context made by ForClient shares its parent's).

func (*Context) StartServices

func (a *Context) StartServices(h Host)

StartServices connects the context to the window shell and starts the background services of the window: persisted UI preferences, the minimise/close-to-tray setting (followed live through /config/events) and OS notifications for runs finishing while the window is unfocused. Call it on the UI thread once the window exists. h may be nil (headless).

func (*Context) T

func (a *Context) T(key string, args ...any) string

T translates a key of the Web UI catalogs (i18n.T).

func (*Context) TakeChatDraft

func (a *Context) TakeChatDraft() string

TakeChatDraft returns and clears the pending chat draft.

func (*Context) ToggleSimpleChat

func (a *Context) ToggleSimpleChat()

ToggleSimpleChat switches between the full and the simple chat and remembers the choice (chatMode).

func (*Context) TrayLabels

func (a *Context) TrayLabels() shell.TrayLabels

TrayLabels returns the tray menu labels in the UI language (Web UI keys where they exist; English defaults otherwise).

func (*Context) Update

func (a *Context) Update(fn func())

Update runs fn on the UI thread and redraws. Background goroutines must change view state only through it.

func (*Context) WebViewHost

func (a *Context) WebViewHost() kit.WebViewHost

WebViewHost returns the window that hosts embedded web views (the main window), or nil before it exists and in headless tests. Use it as kit.WebPane.Host:

pane := &kit.WebPane{Host: a.WebViewHost}

type Dispatcher

type Dispatcher interface {
	Update(fn func())
	Invalidate()
}

Dispatcher posts work to the UI thread. *mygo.Window implements it: Update runs fn on the main thread then redraws, Invalidate only redraws. Both are safe from any goroutine and return without waiting.

type ExternalAccess

type ExternalAccess struct {
	Enabled        bool     `json:"enabled"`
	BindHost       string   `json:"bindHost"`
	Port           int      `json:"port"`
	CanToggle      bool     `json:"canToggle"`
	BasicAuthReady bool     `json:"basicAuthReady"`
	URLs           []string `json:"urls"`
}

ExternalAccess mirrors GET/PUT /api/v1/config/api-server/external-access: whether the running server listens on 0.0.0.0 (the Web UI's footer toggle).

type HeaderActions

type HeaderActions interface {
	HeaderActions(c *ui.Context)
}

HeaderActions is implemented by views that add controls to the header bar, on its right.

type HeaderSlot

type HeaderSlot struct {
	ID string
	// Order sorts slots ascending; built-ins use 100+ (simple chat 100,
	// docs 110, theme 120, settings 130).
	Order int
	Build func(c *ui.Context, a *Context)
}

HeaderSlot is a control of the header bar, on the right of the view's own actions. The persona selector registers one with ID "persona".

type Host

type Host interface {
	// Focused reports whether the window has the keyboard focus.
	Focused() bool
	// Show brings the window back (tray, minimised, behind others).
	Show()
	// Quit quits the app, whatever the tray setting.
	Quit()
	// SetTitle sets the window title.
	SetTitle(title string)
	// SetTrayOnClose mirrors Desktop.TrayOnMinimizeClose.
	SetTrayOnClose(on bool)
	// SetTrayProjects lists the open project workspaces in the tray menu.
	SetTrayProjects(p []shell.TrayProject)
	// Notify shows an OS notification.
	Notify(id, title, body string)
}

Host is what the window shell (internal/nativeui/shell) offers the app: *shell.Controller implements it. It is nil in headless tests, so callers go through the Shell helpers, which tolerate that.

type LeaveGuard

type LeaveGuard interface {
	ConfirmLeave(proceed func()) bool
}

LeaveGuard is implemented by views that hold unsaved edits (settings). The layout asks it before navigating to another area: ConfirmLeave returns true when leaving is fine right now; otherwise it shows its own prompt and calls proceed later if the user decides to leave.

type Overlay

type Overlay interface {
	Build(c *ui.Context)
}

Overlay is a layer drawn above the whole window (dialogs, palettes). Build runs every frame on the main tab; it draws nothing while closed.

type QueueDispatcher

type QueueDispatcher struct {
	// contains filtered or unexported fields
}

QueueDispatcher is a Dispatcher for tests and headless use: Update queues fn until Drain runs the queue on the caller's goroutine.

func (*QueueDispatcher) Drain

func (q *QueueDispatcher) Drain() int

Drain runs the queued functions (and those they queue) and reports how many ran.

func (*QueueDispatcher) Invalidate

func (q *QueueDispatcher) Invalidate()

Invalidate counts a redraw request.

func (*QueueDispatcher) Update

func (q *QueueDispatcher) Update(fn func())

Update queues fn.

type Root

type Root struct {
	App *Context
	// contains filtered or unexported fields
}

Root is the window's view: sidebar, header and the routed area.

func NewEmbeddedRoot

func NewEmbeddedRoot(a *Context, brand string) *Root

NewEmbeddedRoot returns a root that lives inside another root (a project workspace tab): it uses the theme of the host frame, shows no toasts, tab bar or theme toggle, and titles its sidebar brand. a is usually made with Context.ForClient.

func NewRoot

func NewRoot(a *Context) *Root

NewRoot returns the root view of a window.

func (*Root) Close

func (r *Root) Close()

Close stops the views that own background work.

func (*Root) View

func (r *Root) View(c *ui.Context)

View builds the window. Pass it to ui.View.

type Section

type Section string

Section groups sidebar entries.

const (
	SectionMain     Section = "main"     // chat, projects
	SectionTools    Section = "tools"    // editor, terminal, orchestrator, ...
	SectionServices Section = "services" // instances, extensions
	SectionBottom   Section = "bottom"   // settings, pinned to the bottom
	SectionHidden   Section = "hidden"   // routable, not in the sidebar (setup)
)

Sidebar sections, top to bottom.

type Shell

type Shell struct {
	// Host is the window shell (nil headless).
	Host Host

	// QuickMenuOpen and ModelSwitcherOpen are the overlays (Ctrl/Cmd+K or
	// Ctrl/Cmd+P, and Ctrl/Cmd+O).
	QuickMenuOpen     bool
	ModelSwitcherOpen bool

	// SidebarCollapsed is the icon-rail sidebar (persisted in the UI
	// preferences).
	SidebarCollapsed bool

	// StartExplicit is set when the first route was chosen (--simple, a
	// path option); otherwise the persisted chat mode may pick it.
	StartExplicit bool

	// NextModel is a model picked in the switcher while no chat session was
	// open: the chat sends it with the first prompt (the web's
	// sessionModelStore). Empty when none.
	NextModel string
	// ModelChanged, when set (the chat sets it), is told after the model
	// switcher changed the model of a session ("" = none open).
	ModelChanged func(model, sessionID string)

	// FocusProject focuses a project workspace tab by project ID (tray
	// menu). The projects area sets it; the default only opens /projects.
	FocusProject func(id string)
	// contains filtered or unexported fields
}

Shell is the window-level state shared by the chrome and the overlays: which overlay is open, the sidebar, the host. UI thread only.

type ShellExt

type ShellExt interface {
	// Tabs lists the open tabs, in order.
	Tabs() []ShellTab
	// Active returns the focused tab ID, "" for the main tab.
	Active() string
	// Select focuses a tab ("" is the main tab).
	Select(id string)
	// Close asks to close a tab (the extension may prompt first).
	Close(id string)
	// Build draws the content of the active tab.
	Build(c *ui.Context, id string)
	// Dialogs draws the extension's modal dialogs; it runs every frame, on
	// whichever tab is focused.
	Dialogs(c *ui.Context)
}

ShellExt adds tabs to the shell. The main tab ("") always exists and shows the routed areas; the extension's tabs replace the whole main panel, sidebar included, with their own content, the way the Web UI shows a project workspace iframe. An extension is created once per root window (never for an embedded root) by the factory given to RegisterShellExt.

type ShellTab

type ShellTab struct {
	ID    string
	Title string
	// Detail is the tooltip (path, state).
	Detail string
	// State is starting, running, stopped or error; it picks the tab icon.
	State string
	// Busy marks a tab whose workspace has an agent run in flight.
	Busy bool
}

ShellTab is a tab of the shell tab bar (a project workspace).

type StatusItem

type StatusItem struct {
	Order int
	// Visible reports whether the item has something to show this frame.
	Visible func(a *Context) bool
	Build   func(c *ui.Context, a *Context)
}

StatusItem is a part of the window's status strip, under the routed area of the main tab (the Web UI's StatusBar slot). Build draws nothing when it has nothing to show; the strip itself only appears when an item drew.

type Titled

type Titled interface {
	Title() string
}

Titled is implemented by views whose header title depends on state (the chat shows the session title). The area's TitleKey is used otherwise.

type View

type View interface {
	Build(c *ui.Context, r *ui.Route)
}

View is what an area shows. Build runs on the UI thread every frame the area is visible; r is the matched route (r.Param for {id} patterns).

type WindowHost

type WindowHost interface {
	// Minimize hides into the tray or minimises, following the tray setting.
	Minimize()
	// ToggleMaximize maximises or restores.
	ToggleMaximize()
	// IsMaximized reports the maximised state.
	IsMaximized() bool
	// CloseWindow hides into the tray or closes (quitting), following the
	// tray setting.
	CloseWindow()
	// ToggleFullScreen toggles full screen.
	ToggleFullScreen()
}

WindowHost is the part of the host that drives the window for the custom title bar (Linux, Windows); *shell.Controller implements it.

Directories

Path Synopsis
Package agentvcs is the Agent VCS area (route /snapshots, as in the Web UI): the sessions that have agent commits, their commit log, the files each commit changed with a side-by-side diff viewer (MyGo ui/editor DiffView), revert of a commit or of single files, and the named project snapshots.
Package agentvcs is the Agent VCS area (route /snapshots, as in the Web UI): the sessions that have agent commits, their commit log, the files each commit changed with a side-by-side diff viewer (MyGo ui/editor DiffView), revert of a commit or of single files, and the named project snapshots.
Package chat is the chat area of the native desktop: the sessions list, session history and streaming runs (P0 MVP; P1 brings parity with the Web UI: tool cards, diffs, questions, plan/goal, model picker, slash and @).
Package chat is the chat area of the native desktop: the sessions list, session history and streaming runs (P0 MVP; P1 brings parity with the Web UI: tool cards, diffs, questions, plan/goal, model picker, slash and @).
Package design is the Design Studio area of the native desktop: the artifact and template galleries at /design and one artifact's Studio at /design/{id} (web-ui components/design + designStore).
Package design is the Design Studio area of the native desktop: the artifact and template galleries at /design and one artifact's Studio at /design/{id} (web-ui components/design + designStore).
Package editor is the code editor area of the native desktop: a file explorer, open-file tabs, a code editor (MyGo ui/editor, with find bar, folding, multi-cursor and syntax highlighting), image/PDF viewers and a status bar.
Package editor is the code editor area of the native desktop: a file explorer, open-file tabs, a code editor (MyGo ui/editor, with find bar, folding, multi-cursor and syntax highlighting), image/PDF viewers and a status bar.
Package evaluator is the self-improvement area: metrics cards, the daily evaluations chart, the UCB ranking of prompt variants, learned skills with approve/reject, the evaluated sessions with their score explanation and the doctor banner.
Package evaluator is the self-improvement area: metrics cards, the daily evaluations chart, the UCB ranking of prompt variants, learned skills with approve/reject, the evaluated sessions with their score explanation and the doctor banner.
Package extensions is the extension UI of the native desktop: the sidebar page at /ext/{panelId} and the slots (sidebar, settings, chat-side, status-bar) other areas embed.
Package extensions is the extension UI of the native desktop: the sidebar page at /ext/{panelId} and the slots (sidebar, settings, chat-side, status-bar) other areas embed.
Package instances is the instances area: the Pando instances running on this machine grouped by project path, and for the selected one its sessions with the conversation history, the live event stream (/instances/{id}/sessions/{sid}/stream), a message box and cancel.
Package instances is the instances area: the Pando instances running on this machine grouped by project path, and for the selected one its sessions with the conversation history, the live event stream (/instances/{id}/sessions/{sid}/stream), a message box and cancel.
Package logs is the native Logs area: the server log buffer as a table with level and text filters, auto-scroll and a detail panel.
Package logs is the native Logs area: the server log buffer as a table with level and text filters, auto-scroll and a detail panel.
Package orchestrator is the native Orchestrator area: Mesnada tasks (list, detail, create, cancel, delete), delegation metrics and the CronJobs panel.
Package orchestrator is the native Orchestrator area: Mesnada tasks (list, detail, create, cancel, delete), delegation metrics and the CronJobs panel.
Package overlays holds the window-level layers of the native desktop that the Web UI draws over its layout: the quick menu (command palette), the model switcher, the config-init banner and the update notice.
Package overlays holds the window-level layers of the native desktop that the Web UI draws over its layout: the quick menu (command palette), the model switcher, the config-init banner and the update notice.
Package projects is the native Projects area and the project workspaces: the registry of projects (add, rename, stop, delete, init) and the tabs that open a project's child instance inside the shell.
Package projects is the native Projects area and the project workspaces: the registry of projects (add, rename, stop, delete, init) and the tabs that open a project's child instance inside the shell.
Package settings is the settings area of the native desktop: the 23 categories of the Web UI settings (web-ui/src/components/settings), their unsaved-changes guard and the "?section=" deep link.
Package settings is the settings area of the native desktop: the 23 categories of the Web UI settings (web-ui/src/components/settings), their unsaved-changes guard and the "?section=" deep link.
Package setup is the first-run setup assistant of the native desktop (the Web UI's SetupWizard): scope, provider, models, Remembrances and a summary.
Package setup is the first-run setup assistant of the native desktop (the Web UI's SetupWizard): scope, provider, models, Remembrances and a summary.
Package terminal is the Terminal area of the native desktop: tabs of interactive shells running in real PTYs on the server, shown by MyGo's terminal plugin (libghostty-vt, loaded at run time without cgo) and fed by the WebSocket PTY endpoint /api/v1/terminal/pty, the same one the Web UI's xterm.js pane uses (binary frames carry I/O, JSON text frames carry ready/exit/resize/close).
Package terminal is the Terminal area of the native desktop: tabs of interactive shells running in real PTYs on the server, shown by MyGo's terminal plugin (libghostty-vt, loaded at run time without cgo) and fed by the WebSocket PTY endpoint /api/v1/terminal/pty, the same one the Web UI's xterm.js pane uses (binary frames carry I/O, JSON text frames carry ready/exit/resize/close).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL