@guuey/agent-layout
v0.35.0
Published
Agent-mode layout: the two-tone shell where an app and its agent share one surface — the pane follows attention, the transport owns the stream.
Readme
@guuey/agent-layout
Agent-mode layout — the layout category for surfaces where an app and its agent share one screen: app menus in the upper sidebar, the agent rail below, and a content pane whose ground follows the user's attention between the two. Address the agent and the pane takes the agent's tone; navigate and it returns to the app's. One law: layout follows attention; transport owns the stream — the tone flips on submit, never on stream events, and interrupting is the transport's business.
import {
AgentModeProvider,
AgentModeShell,
AgentModeSidebar,
SidebarPanel,
ActivePane,
bindGuueyChat,
useAgentMode,
} from "@guuey/agent-layout/react";
import "@guuey/agent-layout/styles.css";
function Shell() {
const { dispatch } = useAgentMode();
return (
<AgentModeShell>
<AgentModeSidebar>
<SidebarPanel section="app">{/* your menus — zero wiring */}</SidebarPanel>
<SidebarPanel section="agent">
<GuueyChat {...bindGuueyChat(dispatch)} />
</SidebarPanel>
</AgentModeSidebar>
<ActivePane>{/* your routes / canvas */}</ActivePane>
</AgentModeShell>
);
}
<AgentModeProvider mode={mode} navigationKey={pathname} identity={<Logo />}>
<Shell />
</AgentModeProvider>;- Two tones, calibrated: the default pair is the shipped warm-paper/neutral-chrome step, light and dark. Overrides are validated against a perceptibility floor (ΔL* ≥ 6, or a hue-temperature step) — two tones that measure alike are rejected with an explanation.
- Route-derived follow: pass your router's location key as
navigationKey; every navigation returns the pane to the app tone with zero per-link wiring. Same-page menu clicks are caught by the app panel's capture-phase listener. - No stale-content hold: while the agent has the room and nothing is
presented yet, the pane shows a working state (your
identity+ pulse), never the previous page under the agent's tone. - A tall nav scrolls, the agent stays: the app panel is the sidebar's
scroller (a bottom-edge fade shows while items are hidden below it), and
the agent panel never shrinks under its floor, so the composer is always
reachable. The floor is
--guuey-layout-agent-panel-min(default112px:@guuey/chat's header row plus its one-line composer, so nothing is clipped by default). A host that renders the composer alone may lower it; raise it when your agent surface needs more. A host that gives the agent panel a fixed height (--guuey-layout-agent-panel-flex: 0 0 auto) sets--guuey-layout-app-panel-flex: 1 1 auto(default0 1 auto) so the app panel takes the free space and the rail stays at the bottom. - A drawer at phone widths: under 1024px the sidebar becomes an overlay
drawer behind a ☰ toggle. At drawer widths, give the shell the viewport
(
100dvh): the drawer and its toggle are fixed to the viewport, and the toggle sits at its top-left, over anything the host puts above the layout. Escape closes the open drawer, and focus returns to the toggle. - Mode-aware: pass the same
modeyou give your chat surface — the lib rides your existing light/dark machinery and adds none of its own. - Not a chat dependency:
bindGuueyChatpairs with@guuey/chatstructurally; any agent surface can call the machine directly throughuseAgentMode().
React DOM only, zero runtime dependencies. react >= 18 is an optional peer:
the ./react subpath needs it and the root (the attention machine and the tone
helpers) does not, so npm does not install it for you — add react to your own
dependencies when you import @guuey/agent-layout/react.
Support
Questions and help: the guuey community on Discord — https://guuey.com/discord. Bugs and feature requests: https://github.com/withguuey/guuey-sdks/issues.
