- 人工智能
- AI Agent
- Agent记忆
- MCP服务
【免费下载链接】engram
Persistent memory system for AI coding agents. Agent-agnostic Go binary with SQLite + FTS5, MCP server, HTTP API, CLI, and TUI.
Engram 是一个面向 AI 编码代理的持久记忆系统,其云控制面(Cloud Dashboard)是一套基于 Go templ 服务端渲染 + HTMX 局部刷新的浏览器 UI。本文以仓库中的 skills/ui-elements/SKILL.md 为骨架,结合 internal/cloud/dashboard 的真实组件与测试实现,系统讲解在 Engram Dashboard 中新增页面、卡片、指标、表格与详情流时应遵守的设计规则和落地方式。读完本文,你将掌握:何时该用这套规范、五条 UX 铁律与四条组合规则的含义、每条规则对应的 templ/HTMX 组件证据,以及如何通过测试守护"UI 不能撒谎"这一核心不变式。
何时使用这套规范
按 skills/ui-elements/SKILL.md 的When to Use定义,以下场景应当套用本规范:
- 为 Dashboard 新增一个页面或 partial(局部片段);
- 创建卡片(card)、指标(metric)、表格(table)、列表(list)或详情视图(detail view);
- 设计相关实体之间的关联导航(connected navigation)。
在 Engram 中,这些 UI 元素全部落在internal/cloud/dashboard包内,通过 templ 模板(.templ+ 生成的*_templ.go)与 HTMX 属性(hx-get、hx-target、hx-swap、hx-include)组合实现,具体挂载路径可参考 docs/codebase/dashboard.md 中的架构说明:Browser → cloudserver(认证/会话/管理员边界)→ dashboard(handlers + templ + 静态资源)→ DashboardStore 接口 → cloudstore(Postgres 读模型)。
UX 五条铁律:每条都有源码佐证
原文档定义了五条 UX 规则,它们不是空泛的审美建议,而是可以在 components.templ 中逐条对号入座的实现约束。
1. 每条列表项都应通向有用之处
Every list item should lead somewhere useful when domain relationships exist.
当实体之间存在领域关系时,任何列表项都必须是可点击的入口,而不是死胡同。代码中最直接的体现是列表 partial 用<a class="card-link">包裹整张卡片:
ObservationsPartial(components.templ#L328-L352)把每条 observation 包成<a href="/dashboard/observations/{project}/{sessionID}/{syncID}">;PromptsPartial同样把每条 prompt 包成指向详情页的卡片链接;ProjectsListPartial(components.templ#L500-L539)把每个项目包成指向/dashboard/projects/{project}的card-link。
对应测试 dashboard_test.go#L257-L321(TestBrowserObservationsAreClickable、TestBrowserSessionsAreClickable、TestBrowserPromptsAreClickable)逐一断言这些 href 确实存在。
2. 优先使用连接流:project → session → observation → full detail
Prefer connected flows: project -> session -> observation -> full detail.
这是 Engram Dashboard 关联导航的黄金链路,在 URL 结构上体现得尤为清晰(这也是 SKILL 中"connected navigation"的核心实现):
- 项目卡片 →
/dashboard/projects/{project}(ProjectDetailPage); - 项目详情页内通过
#project-tabs三个子标签继续下钻到该项目的 observations / sessions / prompts; - Session 行 →
/dashboard/sessions/{project}/{sessionID}(SessionDetailPage),页面展示会话元数据 + 该会话内的 observations 与 prompts; - Observation 卡片 →
/dashboard/observations/{project}/{sessionID}/{syncID}(ObservationDetailPage),详情页除完整内容外,还带LINKED SESSION面板与"More from this Session"相关列表。
值得注意的细节:observation/prompt 详情 URL 使用syncID而非纯数据库自增 ID,测试TestObservationDetailURLUsesSyncID(dashboard_test.go#L1907)与TestPromptDetailURLUsesSyncID(dashboard_test.go#L1947)专门守护这一约定,确保详情地址与同步合同保持一致。
3. 空状态必须说明缺什么、以及什么能解锁数据
Empty states must explain what is missing and what unlocks data.
EmptyState是 Dashboard 的共享组件(components.templ#L41-L48),渲染NO SIGNAL YET小标题 + 主标题 + 说明文案,配合 styles.css#L856-L871 的居中空状态样式。它在整个界面中大量复用,并且文案始终在回答"缺什么 / 怎么解锁":
- 首页无同步项目时:
"Project metrics will show up here after the first successful sync."——明确指出数据从首次同步解锁; - 无匹配的 observation:
"No observations match the current project, search text, or type filter."——指出是过滤条件导致为空; - 无托管用户:
"Create the first managed user above. Every managed user is deny-by-default and cannot sync any project until an admin grants one explicitly."——既说明缺什么,也说明解锁路径(管理员显式授权项目); - 无项目授权:
"This user is deny-by-default: it cannot sync any project until an admin grants one explicitly above."。
4. 指标必须反映真实系统状态,而不是装饰性计数器
Metrics must reflect real system state, not decorative counters.
首页指标条由DashboardStatsPartial(components.templ#L146-L222)渲染,四个指标卡(Sessions / Observations / Prompts / Projects Synced)全部来自cloudstore.DashboardProjectRow的真实聚合值,汇总函数totalStatSessions、totalStatObservations、totalStatPrompts定义在 helpers.go#L207-L233。每个指标卡同时是stat-card-link,点击直接跳转到对应的过滤视图——指标不仅"真实",还承担导航职责。
Admin 侧同样如此:AdminPage与AdminHealthPage展示的 DB 连接状态、Contributors、Sessions、Observations、Prompts、Projects、Paused Projects 均来自DashboardSystemHealth读模型(components.templ#L755-L802),其中数据库连接直接渲染Connected / Disconnected徽章。
5. 详情页应展示元数据、内容与下一步相关链接
Detail pages should show metadata, content, and the next relevant links.
ObservationDetailPage是标准范本:元数据表(Chunk ID / Session / Created / Tool / Topic Key)→CONTENT区块(结构化内容渲染)→LINKED SESSION面板 →More from this Session相关列表。PromptDetailPage(components.templ#L423-L461)同样在元数据后追加LINKED SESSION与"Other Prompts from this Session"。SessionDetailPage则在会话元数据(Session ID / Project / Directory / Started / Ended / Summary)之外,下钻展示该会话的 Observations 与 Prompts 两组列表。
结构化内容渲染逻辑在 helpers.go#L343-L492:自动识别**What/Why/Where/Learned**结构字段或##标题分节,转成structured-block区块;列表预览则通过renderInlineStructuredPreview压成单行摘要。
组合规则:什么时候用什么元素
原文档给出四条组合规则,配合DashboardStore接口(dashboard.go#L59-L96)能看清每种元素的适用场景:
- 指标用于定位,而不是替代核心内容:
metric-strip/stat-card只承担概览与导航(点击后进入真实内容页),详情本身由 card / table / detail 承载; - 可浏览实体用卡片,密集对比的管理数据用表格:observations 与 prompts 用
.card列表(有标题、预览、时间戳 footer);而 sessions、contributors、admin projects、managed users、audit log 等"密集行数据"统一用.data-table(styles.css#L819-L848),会话表还包在.table-scroll中应对横向溢出(测试TestSessionsTableWrappedInScrollContainer守护); - 避免嵌套框架框:数据面板使用
.data-frame/.browser-content-frame单层边框,.structured-block仅用于表达内容内部层级; - 操作控件要紧贴其作用的实体:项目同步开关直接放在项目行内(
AdminProjectsPage的switch-form,components.templ#L807-L882),启用/禁用按钮紧挨目标项目;托管用户的 Enable/Disable、Revoke 按钮同样各自贴在所属行内。
关联导航的工程化:分页与局部刷新
导航不止是链接,还包括列表翻页体验。Pagination结构(helpers.go#L33-L38)提供Offset/HasPrev/HasNext/ShowPagination/Start/End/PageNumbers全套能力,parsePagination负责把?page=&pageSize=参数钳制在合法范围:默认每页 10 条、最小 10、最大 100,UI 提供{10, 25, 50, 100}四种档位(helpers.go#L21-L30)。
两种分页条分工明确:
PaginationBar(components.templ#L53-L86):完整页面跳转,paginationURL保留现有查询参数(project / q / type 等);HtmxPaginationBar(components.templ#L92-L125):以hx-get向指定 endpoint 发起局部请求,hx-target指向内容容器、hx-include携带现有筛选条件,翻页不刷新整页。注释特别强调 URL 使用?page=而非&page=以避免产生畸形的?&URL。
对应测试TestBrowserPaginationHonorsPageParam、TestBrowserPaginationBeyondTotalClampsToLastPage、TestBrowserPartialRendersPaginationBar(dashboard_test.go)覆盖了页码越界钳制与局部刷新渲染。
核心不变式:UI 不能撒谎
skills/ui-elements/SKILL.md 的精神内核在 docs/codebase/dashboard.md#L45-L47 中被总结为一条硬性架构约束:
The UI cannot lie. If it shows "sync paused", every push path must be blocked server-side.
落实到实现上:
- 项目卡片上的
Paused徽章(ProjectsListPartial)读取的是cloudstore.ProjectSyncControl.SyncEnabled,而真正的执行阻断在cloudserver/cloudstore层(如POST /sync/push、POST /sync/mutations/push的服务器端策略),不是 templ/HTMX 里的摆设; - Admin 项目控制页(
AdminProjectsPage)的每个开关都 POST 到/dashboard/admin/projects/{project}/sync,由 cloudserver 强制执行并审计; - 托管用户(managed users)页面的所有变更表单(create / enable / disable / tokens / grants)也全部指向 cloudserver 拥有的路由,
dashboard包只渲染状态与结果、绝不自行决定授权(见 dashboard.go#L98-L108 的ManagedUsersStore只读边界注释); - 非管理员访问 Admin 面返回 403(
AdminForbidden),测试TestAdminProjectsRequires403ForNonAdmin、TestAdminUsersRequires403ForNonAdmin等一整套 403 用例守护此不变式。
视觉系统:TUI 对齐的设计令牌
static/styles.css 顶部定义了与 TUI 视觉对齐的 CSS 变量:--engram-base: #191724、--engram-surface: #1f1d2e、--engram-primary: #c4a7e7、--engram-success: #9ccfd8、--engram-warning: #f6c177、--engram-danger: #eb6f92等(styles.css#L3-L20)。语义化徽章(StatusBadge)据此着色:decision/architecture → success、bugfix → danger、discovery/learning → warning(helpers.go#L571-L583),头部与按钮使用等宽显示字体族营造终端气质,section-kicker的大写字母间距排版用于区分层级。设计一个"看起来属于 Engram"的新组件,应当复用这些令牌而不是另起一套色板。
用测试守护这套规范
internal/cloud/dashboard/dashboard_test.go是这套 UI 规范最完整的"验收清单",值得在新增组件时对照阅读:
- 可点击性:
TestContributorDetailPageRendersDrillDown、TestBrowserObservationsAreClickable、TestDashboardHomeStatCardsAreClickable(断言 metric-card 必须包在<a>中且 href 指向有意义的钻取视图); - URL 约定:
TestObservationDetailURLUsesSyncID、TestPromptDetailURLUsesSyncID、TestObservationCardHrefIsNotMalformed; - HTMX 接线:
TestMountAddsHTMXNavigationWiringForBrowserProjectsAndAdmin、TestDashboardHomeHTMXWiring、TestBrowserPageHTMXWiring、TestProjectsPageHTMXWiring、TestMountHTMXAndProjectDetailParity; - 空状态与降级:
TestMountStoreErrorsReturnDegradedNon200Responses(store 出错时 htmx 路由返回独立 503 片段而非整页); - 管理权限:一整套 403 用例,以及
TestAdminSyncToggleHTMXPostIncludesFormFields(HTMX 表单必须携带enabled字段)。
这些测试把"每条列表项通向有用之处""指标反映真实状态""详情页带元数据与相关链接"等抽象规则,翻译成了可断言的机器行为——这正是 Engram UI 元素规范能长期不被架空的根本原因。后续新增页面或 partial 时,遵循本文的规则,并参照TestMount...系列测试补齐路由、认证、HTMX partial 与边缘用例即可。
- 人工智能
- AI Agent
- Agent记忆
- MCP服务
【免费下载链接】engram
Persistent memory system for AI coding agents. Agent-agnostic Go binary with SQLite + FTS5, MCP server, HTTP API, CLI, and TUI.
相关推荐
Hugo Blox Tag Cloud 组件实战:为 Markdown Slides 幻灯片站搭建标签导航页
Hugo Blox Tag Cloud 组件实战:为 Markdown Slides 幻灯片站搭建标签导航页 导读 本文以 markdown slides 起始
静态站点前端开发工具Metabase Dashboard Markdown:标题卡片与文本卡片实战指南
Metabase Dashboard Markdown:标题卡片与文本卡片实战指南 导读 本文基于 Metabase 官方仪表板文档( dashboard ma
数据分析数据可视化后端数据库客户端企业应用Nuxt UI v4 ContentNavigation 组件实战指南:基于 @nuxt/content 的手风琴式页面导航
Nuxt UI v4 ContentNavigation 组件实战指南:基于 @nuxt/content 的手风琴式页面导航 导读 UContentNaviga
前端UI组件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考