Adds a Postgres-backed quotes domain (poems/quotes/favorites) exposed as five agent-native actions (list-quotes, get-random-quote, create-quote, toggle-favorite, list-favorites) callable from both chat and the React UI via useActionQuery/useActionMutation. Moves the primary UI from chat to a mobile-first Quotes/Favorites experience (chat moves to /chat), adds manual OpenTelemetry instrumentation exporting traces/metrics/logs over OTLP, and wires a local Docker Postgres for shared state.
5.5 KiB
Verse — Agent Guide
Verse is a quote app built on poems: browse, search, and favorite quotes drawn
from poems, or submit new ones. It started from the agent-native chat template,
but the primary surface is the quotes UI at / — chat lives at /chat and is
a secondary way to reach the same actions (see "Domain & Actions" below).
Core Rules
- Store large file/blob payloads in configured file/blob storage, not SQL: no
base64,
data:URLs, images, video/audio, PDFs, ZIPs, screenshots, thumbnails, or replay chunks in app tables,application_state,settings, orresources; persist URLs, ids, or handles instead. - Never hardcode API keys, tokens, webhook URLs, signing secrets, private Builder/internal data, customer data, or credential-looking literals. Use secrets/OAuth/runtime configuration and obvious placeholders in examples.
- Follow the root framework contract: data in SQL, actions first, application state for navigation/selection, and shared agent chat for AI work.
- Use actions for app operations and keep frontend/API parity.
- Treat the chat as the default UI. When the user asks for a capability, prefer adding or improving the action surface first, then add a page, table, form, or widget only when the user needs to inspect, compare, approve, or share durable objects.
- If the user wants to plug in their own agent backend, keep the app shell and
thread UI intact and adapt the chat through the framework's
AgentChatRuntimeconnector helpers instead of forking the transcript/composer UI. - Keep the action surface small and orthogonal: every action is a tool in the
model's context window, so prefer one CRUD-style
update(patch of fields) over many per-field actions, reach for an existing generic query / escape hatch (provider-api-*, devdb-query) before minting a new read action, mark UI-only or programmatic actionsagentTool: falseto hide them from the model (distinct fromtoolCallable: false, which only gates the extension iframe), and delete or hide actions the UI no longer uses. See theactionsskill. - Keep database code provider-agnostic and additive.
- Use
view-screenor application state when the active page/selection is unclear. - For new features, update UI, actions, skills/instructions, and application state when applicable.
Domain & Actions
Data model: poems (author, title, source, year) → quotes (text, tags,
is_user_submitted) → favorites (quote_id, visitor_id). visitor_id is an
anonymous per-browser id (localStorage), not a login — there is no user
account system in this app; AUTH_DISABLED=true by default since no Zitadel
client is configured for this instance.
- list-quotes (GET) — browse/search quotes. Optional
tag,author,search(free text over quote + poem title),visitorId(marksisFavoritedon each result),favoritesOnly,limit. Use this for any "show me quotes about X" / "quotes by Y" request. - get-random-quote (GET) — one random quote, optionally filtered by
tag. Use for "quote of the day" / "surprise me" requests. - create-quote (POST) — submit a new quote. Requires
text,author,poemTitle; optionalsource,year,tags. Creates the poem record if author+title doesn't already exist (case-sensitive exact match). Marks the quoteis_user_submitted: true. - toggle-favorite (POST) — favorite/unfavorite a quote for a
visitorId(toggles based on current state, no separate favorite/unfavorite actions). Returns{ favorited, favoriteCount }. - list-favorites (GET) — all quotes a
visitorIdhas favorited, most recent first. RequiresvisitorId.
All five are callable from chat and from the React UI via
useActionQuery/useActionMutation — there is no separate /api/* REST
layer. Every action call emits an OpenTelemetry span, a structured log line,
and increments a call counter, exported over OTLP to the shared Grafana LGTM
stack (see server/otel.ts).
Application State
navigationshould describe the current view and selected entity ids. The quotes home view isquotesat/; chat is a secondary view at/chat.navigatemay be used to move the UI when the app supports it.view-screenis the first tool to call when the user's visible context matters.
Framework Docs Lookup
- Before implementing or explaining non-trivial Agent Native behavior, use the
agent-native-docsskill and the built-indocs-searchaction/tool to read the version-matched framework docs bundled with@agent-native/core. - Use the built-in
source-searchaction/tool, or searchnode_modules/@agent-native/core/corpus, when you need current core or first-party template implementation examples. - Prefer those installed docs over memory or public docs when package APIs, generated-app conventions, workspaces, actions, or agent surfaces are involved.
- Before building common workspace or agent UI, read
agent-native-toolkitto inventory existing public kits and installed package seams. - Read
customizing-agent-nativebefore overriding the chat shell or shared UI. Keep Core thread/runtime behavior and use the supported ladder: configure → compose → eject the smallest presentation unit → propose a shared seam. Preview before--applyand commitagent-native.ejections.json.
Skills
Read the relevant root skill before implementation: adding-a-feature,
actions, agent-native-docs, agent-native-toolkit,
customizing-agent-native, storing-data,
real-time-sync, security, delegate-to-agent, frontend-design, shadcn-ui, and
self-modifying-code.