<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Bob Lee</title>
    <description>The latest articles on DEV Community by Bob Lee (@bobleer).</description>
    <link>https://dev.to/bobleer</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4065857%2F1e3b9fd6-c7c1-429a-a5a5-4d2695197bf2.jpg</url>
      <title>DEV Community: Bob Lee</title>
      <link>https://dev.to/bobleer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bobleer"/>
    <language>en</language>
    <item>
      <title>Your AI Task Should Not End as a Chat Transcript</title>
      <dc:creator>Bob Lee</dc:creator>
      <pubDate>Thu, 06 Aug 2026 11:59:47 +0000</pubDate>
      <link>https://dev.to/bobleer/your-ai-task-should-not-end-as-a-chat-transcript-ljg</link>
      <guid>https://dev.to/bobleer/your-ai-task-should-not-end-as-a-chat-transcript-ljg</guid>
      <description>&lt;p&gt;Chat is an excellent way to begin a task. It is a surprisingly poor place for many tasks to end.&lt;/p&gt;

&lt;p&gt;Ask an assistant to investigate a repository, compare options, or manage a review queue, and useful state soon disappears into a vertical transcript: what is selected, what changed, which result is current, and what remains blocked. Returning later means reconstructing an application-shaped problem from messages written for an earlier moment.&lt;/p&gt;

&lt;p&gt;This is not only a model problem. It is an interface problem.&lt;/p&gt;

&lt;p&gt;A calendar wants a calendar. A dependency graph wants a graph. A review queue wants rows, filters, and explicit status. Conversation can remain the command surface, but structured work needs a &lt;strong&gt;task surface&lt;/strong&gt; that owns its state and exposes the right actions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; I maintain &lt;a href="https://github.com/GCWing/BitFun" rel="noopener noreferrer"&gt;BitFun&lt;/a&gt;, the implementation used as the source-linked case study below. I also used AI assistance to organize and edit this article, then checked every product-specific claim against pinned source code. The design pattern is the point; this is not an independent security audit or performance evaluation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The missing object between chat and automation
&lt;/h2&gt;

&lt;p&gt;Traditional chat has messages and attachments. Traditional automation has fixed inputs and outputs. Stateful agent work needs a third object between them: an interface that represents the task as it exists &lt;em&gt;now&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That interface should own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;domain objects and their current status;&lt;/li&gt;
&lt;li&gt;selections, filters, view mode, and revision;&lt;/li&gt;
&lt;li&gt;the relationship between an agent action and the object it affects;&lt;/li&gt;
&lt;li&gt;a place to inspect, accept, reject, or revise the result.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key design decision is that the model does not magically “see the UI.” The application chooses a small, explicit snapshot of relevant state when the user submits a request. That snapshot becomes part of a versionable protocol.&lt;/p&gt;

&lt;p&gt;This distinction matters. “What happens if I remove this node?” is ambiguous in a transcript. A dependency explorer can make it precise by sending the selected node ID, visible dependency set, active filters, and graph revision. It does not need to send the entire DOM, a screenshot, or every object in memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  A reference architecture
&lt;/h2&gt;

&lt;p&gt;BitFun's current Mini App implementation separates four responsibilities:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Mini App owns presentation and domain state.&lt;/strong&gt; Its source model has an HTML/CSS/ESM browser layer and can support worker logic in non-marketplace profiles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The desktop host owns privileged capabilities.&lt;/strong&gt; The iframe calls an injected &lt;code&gt;window.app&lt;/code&gt; bridge; filesystem, network, shell, AI, Agent, notifications, and host UI are represented as explicit capability groups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An owned agent session supplies continuity.&lt;/strong&gt; A Mini App can create or restore a dedicated session, reuse it for later turns, and receive progress only for sessions associated with that app instance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The normal scheduler owns execution.&lt;/strong&gt; A Mini App agent turn is submitted through the same dialog scheduler used by the desktop runtime; it may start immediately or be queued.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The data flow is compact:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;shared composer
      │  token-scoped user message
      ▼
sandboxed task UI ── relevant state snapshot ──► host bridge
      ▲                                             │
      │  session-filtered progress                  │ permission + ownership checks
      └──────────── owned agent session ◄───────────┘
                                  │
                                  ▼
                           dialog scheduler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are two boundaries worth noticing.&lt;/p&gt;

&lt;p&gt;First, the bridge is an API boundary, not an invitation to expose the whole desktop object graph. The public contract offers named operations such as &lt;code&gt;agent.ensureSession&lt;/code&gt;, &lt;code&gt;agent.run&lt;/code&gt;, &lt;code&gt;chat.claimComposer&lt;/code&gt;, and &lt;code&gt;chat.focusSession&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Second, session identity is part of authorization. Reusing a session is accepted only when its recorded owner matches the Mini App and its workspace matches the expected path. The web host separately tracks which sessions the current iframe started before allowing one to appear in the shared conversation surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Binding conversation to the task surface
&lt;/h2&gt;

&lt;p&gt;The current API makes the binding explicit rather than implicit.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Claim the shared composer
&lt;/h3&gt;

&lt;p&gt;An agent-backed Mini App can call &lt;code&gt;app.chat.claimComposer()&lt;/code&gt;. While its tab is active, messages from the shared input are routed to that exact iframe as &lt;code&gt;chat:userMessage&lt;/code&gt; events.&lt;/p&gt;

&lt;p&gt;The claim is scoped by a per-runner token, not only an app ID. That matters because an installed app and a draft preview can share an ID while both are alive. The token prevents one submission from reaching both runners.&lt;/p&gt;

&lt;p&gt;The Mini App may contribute bounded text such as a title, placeholder, and example prompts. The host still renders and owns the input component; the iframe cannot replace it with arbitrary host markup.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Create or restore an owned session
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;app.agent.ensureSession()&lt;/code&gt; creates a dedicated session or validates a requested existing session. &lt;code&gt;app.chat.focusSession()&lt;/code&gt; then associates that known session with the Mini App's composer claim.&lt;/p&gt;

&lt;p&gt;The separation is useful: “which interface receives this input?” and “which agent history should be visible?” are related questions, but they are not the same question.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Snapshot state at submission time
&lt;/h3&gt;

&lt;p&gt;The host accepts a user-facing &lt;code&gt;displayText&lt;/code&gt; separately from the Mini App's internal &lt;code&gt;prompt&lt;/code&gt;. The transcript can therefore preserve what the user actually wrote while the agent receives a structured task protocol.&lt;/p&gt;

&lt;p&gt;Here is the pattern in simplified form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;claimComposer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Dependency Explorer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;composer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Ask about the current graph…&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;topic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ensureSession&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;sessionName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Dependency Explorer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;appDataWorkspace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;topics/current&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;focusSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onUserMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;displayText&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;collectRelevantState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// app-owned model, not DOM scraping&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dependency-explorer/v1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;state&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;displayText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;displayText&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;collectRelevantState()&lt;/code&gt; is deliberately application-specific. A production Mini App also needs an output contract: parse the result, reject malformed or stale revisions, and apply only validated changes. Starting an agent turn is asynchronous; progress and completion arrive as session-filtered events rather than as a magical synchronous answer from &lt;code&gt;agent.run()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why explicit state beats a giant prompt
&lt;/h2&gt;

&lt;p&gt;The goal is not to serialize the entire application on every turn. A useful task surface creates a narrow boundary:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep durable domain state in the application.&lt;/li&gt;
&lt;li&gt;Send only the state relevant to the current action.&lt;/li&gt;
&lt;li&gt;Preserve the user's words separately from the internal protocol.&lt;/li&gt;
&lt;li&gt;Reuse a session only when conversational continuity is useful.&lt;/li&gt;
&lt;li&gt;Include a revision or other freshness signal when stale output would be harmful.&lt;/li&gt;
&lt;li&gt;Validate agent output before changing application state or external resources.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This makes context inspectable. Developers can unit-test the snapshot, users can see the selected object, and maintainers can version the protocol. It also gives you a clear place to redact secrets and cap payload size.&lt;/p&gt;

&lt;h2&gt;
  
  
  Capability should follow the task, not the iframe
&lt;/h2&gt;

&lt;p&gt;A stateful interface is useful only if its authority is equally specific.&lt;/p&gt;

&lt;p&gt;BitFun's manifest model separates filesystem, shell, network, Node, direct AI, full Agent, notifications, and host-UI permissions. Shell access is expressed as a command allowlist, network access as a domain allowlist, and Agent access has its own enabled flag and optional per-minute limit. Host-side handlers check these gates before servicing bridge calls.&lt;/p&gt;

&lt;p&gt;The current public-market profile is intentionally stricter than the general source model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;marketplace packages must explicitly disable Node;&lt;/li&gt;
&lt;li&gt;remote imports and dynamic code evaluation are rejected during package validation;&lt;/li&gt;
&lt;li&gt;broad home-directory and absolute filesystem scopes are rejected;&lt;/li&gt;
&lt;li&gt;marketplace iframes run with &lt;code&gt;sandbox="allow-scripts"&lt;/code&gt;, without same-origin access;&lt;/li&gt;
&lt;li&gt;hidden Agent turns from marketplace Mini Apps use a small allowlist centered on read-only web research rather than filesystem, shell, or host control.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are concrete controls, not a claim of perfect isolation. Human review, manifests, iframe sandboxing, and allowlists reduce different risks; none of them makes untrusted code inherently safe.&lt;/p&gt;

&lt;p&gt;The implementation also retains a compatibility profile for built-in or local Mini Apps with a broader iframe sandbox and optional worker support. Therefore, statements about the marketplace strict profile should not be generalized to every Mini App. That split is visible in the runner code and is an important part of the threat model.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this pattern does—and does not—solve
&lt;/h2&gt;

&lt;p&gt;It solves a real interface problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the user can point at an object instead of redescribing it;&lt;/li&gt;
&lt;li&gt;follow-up turns can continue in the task's own agent session;&lt;/li&gt;
&lt;li&gt;progress can appear beside the state it affects;&lt;/li&gt;
&lt;li&gt;permissions and ownership checks have explicit enforcement points.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It does &lt;strong&gt;not&lt;/strong&gt; give the model automatic access to arbitrary UI state. It does not remove the need to design state and output schemas. It does not guarantee correct model output. It does not turn an iframe sandbox into a complete security boundary, and it does not make every task better as an app.&lt;/p&gt;

&lt;p&gt;A one-off explanation probably belongs in chat. A task becomes a strong Mini App candidate when it has several of these properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;state changes over multiple turns;&lt;/li&gt;
&lt;li&gt;the user repeatedly selects or compares objects;&lt;/li&gt;
&lt;li&gt;the output needs review before it is applied;&lt;/li&gt;
&lt;li&gt;the same workflow will be reopened;&lt;/li&gt;
&lt;li&gt;a domain-specific visualization reveals more than prose.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  From answer-shaped output to software-shaped work
&lt;/h2&gt;

&lt;p&gt;Chat should not disappear. It is flexible, forgiving, and often the fastest way to express intent. But a transcript should be one view of the work, not its only container.&lt;/p&gt;

&lt;p&gt;The reusable idea is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;conversation supplies intent;&lt;/li&gt;
&lt;li&gt;the task surface supplies structure and controls;&lt;/li&gt;
&lt;li&gt;an owned session supplies continuity;&lt;/li&gt;
&lt;li&gt;explicit state and host-mediated capabilities connect them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;BitFun is one current implementation of that pattern, not proof that the pattern is finished. Its public gallery is still early, which makes the source more useful than adoption claims for evaluating the architecture.&lt;/p&gt;

&lt;p&gt;For verification rather than endorsement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://market.openbitfun.com/miniapp/" rel="noopener noreferrer"&gt;Live Mini App gallery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun" rel="noopener noreferrer"&gt;BitFun source repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/releases/latest" rel="noopener noreferrer"&gt;Latest public release and platform builds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/tree/e1dbe2ac3a7fd853f84b47711169d82c91fec32f/src/crates/contracts/product-domains/src/miniapp" rel="noopener noreferrer"&gt;Pinned Mini App implementation reviewed for this article&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Source notes
&lt;/h2&gt;

&lt;p&gt;The product-specific statements above were checked against these source locations, pinned so future changes do not silently move the evidence:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/blob/e1dbe2ac3a7fd853f84b47711169d82c91fec32f/src/crates/contracts/product-domains/src/miniapp/types.rs#L23-L38" rel="noopener noreferrer"&gt;Browser UI and optional worker source model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/blob/e1dbe2ac3a7fd853f84b47711169d82c91fec32f/src/crates/contracts/product-domains/src/miniapp/types.rs#L40-L130" rel="noopener noreferrer"&gt;Capability groups, allowlists, and Agent limits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/blob/e1dbe2ac3a7fd853f84b47711169d82c91fec32f/src/crates/contracts/product-domains/src/miniapp/types.rs#L139-L159" rel="noopener noreferrer"&gt;Host UI capability flags&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/blob/e1dbe2ac3a7fd853f84b47711169d82c91fec32f/src/crates/contracts/product-domains/src/miniapp/bridge_builder.rs#L120-L162" rel="noopener noreferrer"&gt;&lt;code&gt;window.app&lt;/code&gt; Agent and chat bridge contract&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/blob/e1dbe2ac3a7fd853f84b47711169d82c91fec32f/src/web-ui/src/app/scenes/miniapps/components/MiniAppRunner.tsx#L81-L119" rel="noopener noreferrer"&gt;Strict and compatibility iframe profiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/blob/e1dbe2ac3a7fd853f84b47711169d82c91fec32f/src/web-ui/src/app/scenes/miniapps/hooks/useMiniAppBridge.ts#L325-L423" rel="noopener noreferrer"&gt;Agent permission checks and session registration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/blob/e1dbe2ac3a7fd853f84b47711169d82c91fec32f/src/web-ui/src/app/scenes/miniapps/hooks/useMiniAppBridge.ts#L452-L529" rel="noopener noreferrer"&gt;Composer permission, claim, and session-focus checks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/blob/e1dbe2ac3a7fd853f84b47711169d82c91fec32f/src/web-ui/src/app/scenes/miniapps/hooks/useMiniAppBridge.ts#L658-L688" rel="noopener noreferrer"&gt;Token-scoped user-message routing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/blob/e1dbe2ac3a7fd853f84b47711169d82c91fec32f/src/web-ui/src/app/scenes/miniapps/hooks/useMiniAppBridge.ts#L724-L781" rel="noopener noreferrer"&gt;Session-filtered Agent event forwarding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/blob/e1dbe2ac3a7fd853f84b47711169d82c91fec32f/src/apps/desktop/src/api/miniapp_agent_api.rs#L90-L135" rel="noopener noreferrer"&gt;Separate internal prompt and user-facing display text&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/blob/e1dbe2ac3a7fd853f84b47711169d82c91fec32f/src/apps/desktop/src/api/miniapp_agent_api.rs#L455-L510" rel="noopener noreferrer"&gt;Session reuse and scheduler submission&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/blob/e1dbe2ac3a7fd853f84b47711169d82c91fec32f/src/crates/contracts/product-domains/src/miniapp/agent_bridge.rs#L271-L285" rel="noopener noreferrer"&gt;Reused-session owner and workspace validation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/blob/e1dbe2ac3a7fd853f84b47711169d82c91fec32f/src/crates/services/miniapp-market-service/src/package.rs#L130-L171" rel="noopener noreferrer"&gt;Marketplace package validation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/blob/e1dbe2ac3a7fd853f84b47711169d82c91fec32f/src/crates/services/miniapp-market-service/src/package.rs#L300-L385" rel="noopener noreferrer"&gt;Marketplace filesystem and dynamic-code restrictions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/GCWing/BitFun/blob/e1dbe2ac3a7fd853f84b47711169d82c91fec32f/src/crates/execution/tool-contracts/src/framework.rs#L2317-L2357" rel="noopener noreferrer"&gt;Marketplace Agent tool allowlist&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
