Apps that work with their agent
Keep an open app current when an agent changes its data, and pass the user's actions and context back to the chat.
What the app and agent can do together
Show agent changes without a reload. If an agent changes the app from another chat, device, or scheduled action, an open view can update as soon as the change arrives.
Give the next agent turn useful context. The app can tell a connected agent which item the user selected, what the user can see, or which action they just took. This adds context without posting a chat message.
Start a follow-up from the app. A button can send a user message into the connected chat, such as asking the agent to plan work from the project on screen.
Keep the standalone app useful. A direct visit has no connected agent thread. The app can detect that case, keep its normal controls working, and hide actions that need a chat.
Technical
Use the injected window.charming runtime for live updates and host communication. The Browser runtime API defines every method and failure shape.
Copy this prompt for your agent
Make my Charming app work with its connected agent. Read
https://charm.ing/docs/guides/agent-connected-apps.md first. Keep the
open UI current when the agent changes data, and pass useful user
actions or view state back to the agent. Ask me before adding any
button that posts a new message to the chat.
If you haven't built a Charming app before, read
https://charm.ing/docs/build-mcp.md for MCP or
https://charm.ing/docs/build-http.md for HTTP before you start.
Refresh when the agent changes data
Subscribe once after the app renders. An operation event names the operation and includes its unwrapped result when the JSON response body is no larger than 32 KiB (32 kibibytes). If result is null, refetch unless null is a valid result for that operation. A reconnect event always requires a full refetch.
const api = window.charming.api('project-board');
async function refresh() {
render(await api.getBoard());
}
void refresh();
const unsubscribe = window.charming.onStateChange(async (event) => {
if (event.source === 'reconnect-resync') {
await refresh();
return;
}
if (event.op === 'moveTask' && event.result) {
updateTaskCard(event.result);
} else {
await refresh();
}
});
Change only the affected DOM nodes when the event result has enough data. A full rerender can discard text the user is typing, focus, and selection. Keep the unsubscribe function if the UI can remove or replace the subscribed view.
Send context without starting a turn
Use updateContext() for the latest state and recordAction() for a short history of user actions. Both are dropped when no agent host is connected.
function selectProject(project) {
showProject(project);
window.charming.updateContext({
selectedProject: { id: project.id, name: project.name },
});
window.charming.recordAction('selected-project', {
projectId: project.id,
});
}
Send the least context the agent needs. Do not send credentials, private browser state, or data that the next agent turn does not need.
Send an explicit follow-up
Use sendFollowUp() only after a clear user action. It posts a user message and can start a model turn, unlike the silent context methods.
const planButton = document.querySelector('[data-plan-project]');
function syncAgentControls() {
planButton.hidden = !window.charming.isConnected;
}
syncAgentControls();
window.charming.onConnectionChange(syncAgentControls);
planButton.addEventListener('click', () => {
window.charming.sendFollowUp('Plan the next three tasks for the selected project.');
});
onConnectionChange() passes the new boolean value to its callback, but a callback can also read isConnected as shown above. It does not run once at subscription time, so set the initial state yourself.
Open links through the host
Use openLink() for an external HTTP or HTTPS URL. It asks an embedded chat host to open the link and falls back to a safe new tab during direct browsing.
docsButton.addEventListener('click', () => {
window.charming.openLink(project.docsUrl);
});
Contract details
See Live state for event sources, result limits, and reconnect behavior. See Agent host connection for connection state, message rate limits, context merge behavior, and action history.