What Is the `application_state` Table in Agent-Native?
The application_state table is a session-scoped, SQL-backed key-value store that persists transient UI and navigation data for agents and front-end components in the BuilderIO/agent-native framework.
The application_state table serves as the central coordination mechanism in Agent-Native, enabling seamless state synchronization between AI agents and user interfaces. Unlike permanent user data models, this table stores ephemeral information such as form drafts, navigation commands, and refresh flags that survive page reloads but remain strictly isolated to specific user sessions.
Architecture and Design
The application_state table acts as a shared, persistent context layer that bridges the gap between server-side agent logic and client-side UI components. It ensures that short-lived state survives browser refreshes while maintaining strict data isolation between concurrent users.
Ephemeral Data Storage
Each row in the application_state table stores transient data that agents and UIs need to access without polluting the permanent data model. Common use cases include:
- Draft content and form selections
- Navigation commands and URL synchronization data
- Refresh-screen flags and UI update triggers
- Temporary agent context that must persist across tool calls
Session-Scoped Isolation
The table implements strict session scoping through a session_id column. This design ensures that concurrent users or multiple agents operating simultaneously never clash over shared keys. According to the scoping configuration in packages/core/src/scripts/db/scoping.ts, the table is declared as an exact-match scoped table, meaning all queries are automatically filtered to the current user and organization context.
Database Schema
The table schema follows a simple key-value structure managed by Drizzle:
session_id– Identifies the user session for isolationkey– String identifier for the state entry (e.g.,draft:post,navigation:command)value– JSON-serialized data payloadupdated_at– Timestamp for tracking modifications
The migration script in scripts/qa-public-share-smoke.ts ensures the table exists on fresh databases by executing CREATE TABLE IF NOT EXISTS application_state (...).
Client API Implementation
Front-end applications interact with the application_state table through a typed client API located in packages/core/src/client/application-state.ts. This layer handles HTTP communication, JSON serialization, and request validation.
The client functions communicate with the internal route /_agent-native/application-state/:key, providing a RESTful interface for state management.
Reading State Values
Use readClientAppState to retrieve typed data from the table:
import { readClientAppState } from '@agent-native/core/client';
async function getDraft() {
const draft = await readClientAppState<{ title: string; body: string }>(
'draft:post',
);
console.log('Current draft:', draft);
}
This executes a GET request to /_agent-native/application-state/draft:post and returns the stored JSON or null if the key does not exist.
Writing State Values
Use writeClientAppState to persist data with optional metadata:
import { writeClientAppState } from '@agent-native/core/client';
async function saveDraft(data: { title: string; body: string }) {
await writeClientAppState('draft:post', data, {
requestSource: 'ui',
});
}
Internally, this performs a PUT request with Content-Type: application/json. The requestSource parameter enables audit logging by tagging the origin of the write operation.
Deleting State Keys
Use setClientAppState with undefined or null to remove entries:
import { setClientAppState } from '@agent-native/core/client';
async function clearDraft() {
await setClientAppState('draft:post', undefined); // deletes the row
}
The deleteClientAppState function provides an explicit alternative for removal operations.
Server-Side Integration
The server implementation treats application_state as both an observation target and a read-only data source for agent tools.
Polling and UI Synchronization
The polling system in packages/core/src/server/poll.ts actively monitors the application_state table for changes to specific keys like refresh-screen and set-url. When detected, the server broadcasts updates to connected front-end clients, enabling real-time UI synchronization without requiring full page reloads or action-layer round trips.
Database Tool Access
Server-side tools can query the table using the db-query tool, though writes should route through the client API to maintain scoping and audit consistency:
import { dbQuery } from '@agent-native/core/server';
async function getAllNavCommands(sessionId: string) {
const rows = await dbQuery(
`SELECT key, value FROM application_state WHERE session_id = $1`,
[sessionId],
);
return rows;
}
The framework documentation in packages/core/src/server/prompts/framework-core.ts instructs LLM agents to use specific readAppState and writeAppState tools rather than direct SQL manipulation, ensuring proper access patterns.
Key Source Files
| Area | File | Purpose |
|---|---|---|
| Client API | packages/core/src/client/application-state.ts |
Typed functions (readClientAppState, writeClientAppState, setClientAppState, deleteClientAppState) for front-end state management |
| Server Polling | packages/core/src/server/poll.ts |
Watches table changes and pushes real-time updates to the UI |
| Database Schema | scripts/qa-public-share-smoke.ts |
Contains CREATE TABLE IF NOT EXISTS application_state migration logic |
| Scoping Configuration | packages/core/src/scripts/db/scoping.ts |
Declares application_state as a session-scoped table with session_id column filtering |
| Agent Documentation | packages/core/src/server/prompts/framework-core.ts |
Explains LLM tool usage for application_state interactions |
Summary
- The
application_statetable provides a session-scoped, SQL-backed key-value store for transient UI and agent data in Agent-Native. - Data is automatically isolated by
session_idand scoped to the current user organization, preventing cross-session contamination. - Front-end applications use the client API in
application-state.tsto read, write, and delete values via HTTP requests to/_agent-native/application-state/:key. - The server polling mechanism monitors the table for navigation and refresh commands, pushing real-time updates to connected clients.
- While server tools can query the table via
db-query, writes should use the typed client API to preserve scoping rules and audit trails.
Frequently Asked Questions
What types of data should be stored in the application_state table?
Store only ephemeral, UI-specific data such as form drafts, navigation commands, refresh flags, and temporary agent context. Do not use this table for permanent user data or business-critical information that requires long-term persistence, as it is designed for short-lived state that can be safely discarded after the session ends.
How does Agent-Native prevent session collisions in the application_state table?
The table uses a session_id column combined with automatic scoping logic defined in packages/core/src/scripts/db/scoping.ts. Every query is filtered to the current session, ensuring that users or agents operating in different sessions cannot read or overwrite each other's state entries even if they use identical keys.
Can agents write directly to the application_state table using SQL tools?
While agents can read from the table using the db-query tool, direct SQL writes are discouraged. The framework provides specific writeAppState and setClientAppState tools that route through the HTTP API, ensuring proper JSON serialization, audit logging via requestSource headers, and enforcement of scoping rules that raw SQL might bypass.
Where is the application_state table schema defined in the source code?
The schema is defined in the migration script located at scripts/qa-public-share-smoke.ts, which executes CREATE TABLE IF NOT EXISTS application_state (session_id, key, value, updated_at). Additionally, the scoping configuration in packages/core/src/scripts/db/scoping.ts registers the table as an exact-match scoped entity within the Drizzle ORM configuration.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →