Na Alpic, acreditamos que a próxima geração de produtos e serviços será construída em torno de experiências centradas em IA, com interfaces em que os usuários colaboram com modelos em vez de navegar por fluxos tradicionais e predeterminados da interface.
Quando a OpenAI lançou o Apps SDK, começamos a desenvolver com ele imediatamente. Ao longo de três meses, desenvolvemos duas dúzias de Apps do ChatGPT, tanto para uso interno quanto para nossos clientes de segmentos B2B e B2C, como viagens, varejo e SaaS.
Logo no início, descobrimos que criar Apps do ChatGPT é fundamentalmente diferente de criar aplicativos tradicionais para a Web ou dispositivos móveis. Padrões que funcionam bem na Web (busca de dados no momento em que são necessários, estado controlado pela interface, configuração explícita pelo usuário etc.) muitas vezes deixam de funcionar ou chegam a prejudicar a experiência em um ambiente agêntico.
Este artigo reúne as 15 lições mais importantes que aprendemos ao criar Apps do ChatGPT para uso real. Em seguida, mostramos como incorporamos essas lições a um framework de código aberto para a comunidade, o Skybridge, e a uma Habilidade do Codex para ajudar desenvolvedores a idealizar, criar, testar e lançar Apps com muito mais rapidez.
O problema dos três corpos
Nos aplicativos tradicionais para a Web, tudo era simples: havia apenas um usuário e uma interface. Em um aplicativo do ChatGPT, um terceiro corpo entra no sistema: o modelo.
Uma das partes mais difíceis de desenvolver para o ChatGPT é gerenciar o fluxo de informações entre esse trio. Se um usuário clica em um botão "Selecionar" no seu widget, a interface muda visualmente, mas o modelo, o cérebro da conversa, continua sem saber o que aconteceu, a menos que você forneça esse contexto explicitamente. Se o usuário pedir em seguida "Dê mais detalhes sobre este produto" , o modelo não faz ideia do que ele está vendo.
Chamamos isso de assimetria de contexto : cada corpo conhece apenas parte do sistema, e nenhum deles tem a visão completa. Criar bons Apps do ChatGPT não é uma questão de manter tudo sincronizado, mas de decidir quais informações compartilhar, quando compartilhá-las e quem precisa ter acesso a elas. Resolver isso faz a diferença entre um aplicativo pouco fluido e uma experiência agêntica sem atritos.
1. Nem todo contexto deve ser compartilhado
Nosso primeiro impulso foi “simplesmente compartilhar tudo em todos os lugares”. Esse acabou sendo um dos nossos primeiros erros.
Na prática, diferentes partes de um App do ChatGPT muitas vezes precisam de visões intencionalmente diferentes do mesmo estado. Por quê?
- Por questões de desempenho: os widgets da interface costumam precisar de muito mais dados do que o modelo jamais deveria precisar. Em um aplicativo de reservas de viagens, por exemplo, isso pode incluir imagens, variações de preço e opções pré-carregadas. Enviar tudo isso ao modelo aumentaria o consumo de tokens, a latência e o ruído cognitivo.
- Por questões de lógica: algumas informações precisam permanecer assimétricas por decisão de projeto. Em um dos nossos primeiros aplicativos, o jogo de mistério Murder in the Valleys , o modelo precisa saber quem é o assassino para interpretar seu papel corretamente, enquanto a interface e o usuário não podem saber. Em um jogo no estilo Time’s Up, a situação se inverte: a interface mostra a palavra secreta ao usuário, enquanto o modelo deve continuar sem conhecê-la.
A lição não foi “sempre sincronize tudo”, mas sim: decida explicitamente quem precisa saber o quê. Formalizamos isso usando diferentes campos de saída da ferramenta :
| Campo | Finalidade | Visível para |
|---|---|---|
| structuredContent | Dados tipados para o widget e o modelo | Widget e modelo (por meio das funções toolOutput e callTool) |
| _meta | Metadados da resposta | Somente o widget, ocultos do modelo |
Por exemplo, no jogo Time’s Up, passávamos a palavra secreta apenas ao widget, no campo _meta, para que o modelo tentasse adivinhá-la a partir das dicas do usuário.
2. O carregamento sob demanda não funciona tão bem em aplicativos de IA
Como vínhamos do desenvolvimento para a Web, adotamos por padrão o carregamento sob demanda: buscar dados quando o usuário clica, carregar detalhes conforme necessário e otimizar para enviar o mínimo de dados inicialmente.
No ChatGPT, o paradigma se inverte: as chamadas de ferramentas geram atrasos, muitas vezes de vários segundos, devido à execução em ambiente isolado por segurança e ao raciocínio do modelo.
Na prática, aprendemos a antecipar o máximo possível do carregamento: enviar o maior volume possível de dados na resposta inicial da ferramenta e hidratar o widget por meio de window.openai.toolOutput. Isso quase sempre resultou em uma experiência mais rápida e responsiva.
Claro, se o widget puder buscar dados com segurança em um endpoint público de API e não precisar compartilhar informações com o modelo, sempre será possível usar chamadas XHR tradicionais dentro dele. Mas, na maioria das vezes, você quer que o modelo possa chamar ferramentas de forma autônoma para manter a experiência conversacional.
3. O modelo precisa saber o que está acontecendo
Um problema sutil, mas crítico, surge quando o usuário interage com um widget (por exemplo, selecionando um produto específico em uma lista) e depois faz uma pergunta no chat. Se o modelo não souber a que parte da interface o usuário se refere, não conseguirá responder corretamente.
Para isso, usamos window.openai.setWidgetState(state), que permite armazenar dados específicos de estado que são adicionados ao contexto do modelo na próxima interação entre usuário e modelo.
À medida que os aplicativos ficavam mais complexos, percebemos que estávamos adicionando setWidgetState em muitos lugares para que o modelo acompanhasse a navegação. Por isso, decidimos introduzir uma forma declarativa de descrever o contexto da interface. Em vez de atualizar o modelo de forma imperativa a cada interação, adicionamos um atributo data-llm diretamente aos componentes:
<div
data-llm={
selectedTab === "details"
? "User is viewing product details"
: "User is viewing reviews"
}
>
Para fazer isso funcionar nos bastidores, criamos um plug-in do Vite que extrai esses atributos e atualiza automaticamente o widgetState. Do ponto de vista do modelo, ele simplesmente recebe o contexto relevante da interface no momento certo, sem que os desenvolvedores precisem sincronizar manualmente cada interação.
Você encontra esse plug-in do Vite (e muitas outras dicas que compartilhamos neste artigo) no framework de código aberto que criamos para compartilhar nossos aprendizados com a comunidade.
4. Interações diferentes exigem APIs diferentes
Os Apps do ChatGPT envolvem vários caminhos de interação entre o widget, o servidor e o modelo. Esses caminhos não são intercambiáveis: cada um existe para dar suporte a um tipo diferente de interação.
Uma das principais lições ao criar Apps do ChatGPT é explicitar esses caminhos de comunicação e escolher de forma consciente qual mecanismo é responsável por cada parte da experiência.
Um mapeamento desse caminho fica mais ou menos assim:

Essas lições estabelecem os fundamentos de um App do ChatGPT: como o contexto é compartilhado, como o modelo passa a saber o que está acontecendo e como as diferentes interações se propagam pelo sistema. A próxima seção parte dessa base e se concentra nas implicações para o design de interfaces.
Reinventando a interface para a IA
Os Apps do ChatGPT são um ambiente completamente novo, então logo aprendemos a deixar de lado nossas ideias preconcebidas sobre interfaces e a aproveitar ao máximo os novos recursos. Esta seção aborda as premissas de design de interfaces que precisamos aprender (e desaprender) para criar aplicativos eficazes.
5. A interface precisa se adaptar a vários modos de exibição e às suas restrições
Os Apps do ChatGPT não ficam restritos a um único layout. Dependendo de como e quando são acionados, o mesmo widget pode ser renderizado em três modos de exibição diferentes.
Os Apps podem aparecer no fluxo da conversa, em imagem sobre imagem (PiP) sobre ela ou em tela cheia quando é necessário mais espaço. Embora PiP e tela cheia permitam interfaces mais ricas, também introduzem elementos sobrepostos da interface que o widget não controla. Levar em conta as áreas seguras específicas de cada dispositivo, como o botão de fechar sempre visível em dispositivos móveis, é essencial para evitar cortes no conteúdo e otimizar as interações.
Com o tempo, identificamos padrões de uso dos modos de exibição e situações em que cada um é adequado:
| Como aparece | Quando usar | |
|---|---|---|
| No fluxo da conversa | Modo de exibição padrão. O widget permanece no histórico da conversa. | para interações rápidas |
| Tela cheia | O widget ocupa a tela inteira, com a barra de chat na parte inferior. | se o widget for complexo e precisar de bastante espaço (por exemplo, mapas) |
| Imagem sobre imagem | Mesmo tamanho do modo no fluxo da conversa, mas o widget fica sobre a conversa | se o widget continuar relevante nas interações seguintes da conversa após sua geração |
6. A consistência da interface importa em um ambiente incorporado
Logo no início, uma das nossas dúvidas era quanta liberdade visual um App do ChatGPT deveria ter. Por ser uma interface nova para os usuários, ele precisava transmitir familiaridade e consistência, tanto entre nossos próprios aplicativos quanto em relação ao ecossistema do ChatGPT ao redor. Diferentemente de um produto independente, um widget fica dentro de uma interface existente, na qual as inconsistências visuais se destacam imediatamente.
Felizmente, o OpenAI Apps SDK UI Kit nos deu uma base clara.
Desenvolvido com Tailwind CSS, ele oferece componentes prontos para uso, ícones e tokens de design alinhados ao sistema de design do ChatGPT. Usá-lo nos permitiu avançar rapidamente e garantir que nossos widgets parecessem nativos e visualmente consistentes com o restante da interface, mesmo ao criar componentes personalizados (por exemplo, para nossa integração com o Mapbox).
7. Filtragem centrada na linguagem
Painéis tradicionais são construídos com barras laterais cheias de caixas de seleção e controles deslizantes de intervalo. Em uma interface agêntica, isso costuma ser um retrocesso. Quando os usuários podem expressar sua intenção diretamente em linguagem natural, por exemplo, "Destinos ensolarados na Europa por menos de $200", obrigá-los a passar por vários controles da interface cria obstáculos. Eles deveriam poder simplesmente dizer o que querem.
Por isso, decidimos adotar uma abordagem "sem filtros" na maioria dos nossos aplicativos. Em vez de uma barra lateral com opções de filtragem e ordenação, fornecemos ao modelo uma lista de valores (LOV) para os parâmetros das nossas ferramentas.
Isso permite que o modelo use diretamente a mensagem do usuário como entrada, evitando que precise "adivinhar" quais opções estão disponíveis. Em outras palavras, permite mapear a linguagem natural diretamente para os requisitos da API do nosso backend. Se um usuário disser "ensolarado", o modelo sabe que deve chamar a ferramenta com weather="sunny".
8. Arquivos podem viabilizar interações mais ricas
Uma lição que surgiu à medida que criamos aplicativos mais complexos é que os arquivos não devem ser tratados como entradas secundárias. Nos Apps do ChatGPT, os arquivos podem viabilizar novas interações. Em vez de começar com formulários ou filtros, as experiências podem partir de algo que o usuário já tem.
Por exemplo, em um aplicativo de comércio eletrônico, o usuário pode enviar a foto de um produto no chat, pedir que o modelo o identifique e, em seguida, procurar produtos correspondentes ou descobrir outros produtos diretamente no widget.
Isso é possível ao permitir que os arquivos circulem pelos dois lados do sistema. Do lado do modelo, as ferramentas podem consumir diretamente os arquivos enviados no chat por meio de openai/fileParams, permitindo que o modelo raciocine sobre imagens ou outros materiais fornecidos pelo usuário. Do lado da interface, os widgets também podem trabalhar diretamente com arquivos usando window.openai.uploadFile e window.openai.getFileDownloadUrl, o que permite solicitar uploads como parte do fluxo da interface ou gerar arquivos que os usuários podem baixar e reutilizar.
Levando para produção
À medida que os aplicativos saem do desenvolvimento local, entram em cena novas considerações sobre segurança, configuração e ferramentas. É disso que trata este terceiro conjunto de lições.
9. As CSPs são o novo CORS
Por motivos de segurança, a OpenAI renderiza os Apps dentro de um iframe com dois níveis de aninhamento. As políticas de segurança de conteúdo (CSPs) são um mecanismo nativo de isolamento de iframes, e essa configuração as aplica de forma rigorosa, o que muitas vezes resulta na clássica síndrome do "funciona localmente, mas quebra em produção".
Ao contrário do desenvolvimento web tradicional, em que uma política permissiva pode ser suficiente, o Apps SDK exige precisão cirúrgica.
No manifesto do aplicativo, isso significa declarar com cuidado quais domínios são permitidos para cada tipo de interação:
| Campo | Finalidade | Exemplo | Erros comuns |
|---|---|---|---|
| connectDomains | Requisições de API e XHR | https://api.weather.com | Esquecer que a API de homologação difere da de produção. |
| resourceDomains | Imagens, fontes, scripts | https://cdn.jsdelivr.net | Usar uma CDN genérica como delivr.net sem adicioná-la à lista de permissões |
| frameDomains | Incorporação de iframes | https://www.youtube.com | Incorporar um vídeo do YouTube ou uma instância do Mapbox sem adicioná-los à lista de permissões. |
| redirectDomains | Links externos abertos sem avisos | https://app.alpic.ai | Esquecer o domínio de checkout ou de callback do OAuth. |
Tratar a configuração de CSP como prioridade desde o início nos poupou bastante trabalho de depuração em produção mais adiante.
10. Pequenas flags dos widgets têm grande impacto
Além das CSPs, um pequeno conjunto de configurações do widget determina como o controle é compartilhado entre o widget, o modelo e o ambiente do host. É fácil deixar essas flags passarem despercebidas, mas elas definem limites essenciais para a navegação, o acesso a ferramentas e a publicação.
Limites do host e da navegação
widgetDomainé obrigatório para o envio. Ele define o destino padrão do botão “Abrir em <App>” no modo de tela cheia e participa da definição da lista de origens permitidas, já que os widgets são renderizados em<widgetDomain>.web-sandbox.oaiusercontent.com. UsamossetOpenInAppUrlpara direcionar os usuários ao caminho adequado com base no contexto.
Limites do modelo e das ferramentas
- As anotações das ferramentas devem seguir as diretrizes de publicação. Flags como
readOnly,destructiveHinteopenWorldHintsão obrigatórias e validadas durante o envio. - A visibilidade das ferramentas importa: ferramentas que não devem poder ser chamadas pelo modelo precisam ser explicitamente marcadas como privadas.
Limites de execução do widget
widgetAccessiblecontrola se o widget pode chamar ferramentas por conta própria usandocallTool.
Individualmente, essas configurações são pequenas, mas juntas determinam se um aplicativo se comporta corretamente depois de publicado.
Otimizando para iterar rapidamente
O Apps SDK está evoluindo rapidamente, e tem sido empolgante desenvolver acompanhando essa evolução. Para ter um fluxo de desenvolvimento fluido e eficiente, decidimos criar nosso próprio framework de código aberto e compartilhá-lo com a comunidade. Aqui estão alguns aprendizados para evitar problemas de experiência do desenvolvedor que enfrentamos no início.
11. Iterar rapidamente exige recarregamento a quente
Uma das primeiras questões que abordamos foi a velocidade de iteração. A combinação de cache de recursos com TTL longo e uso de JSON-RPC para encaminhar os recursos faz com que o recarregamento a quente de módulos, em sua forma padrão (como no Vite ou no Next.js), não seja compatível com os Apps do ChatGPT sem adaptações.
Depois de dedicar bastante tempo a entender o funcionamento interno do Vite, criamos um plug-in para ele que permite recarregar widgets em tempo real diretamente no ChatGPT. O plug-in intercepta as requisições de recursos ao servidor MCP e injeta atualizações em tempo real no iframe do ChatGPT. Ver uma alteração na IDE refletida imediatamente no ChatGPT encurtou muito nosso ciclo de feedback.

12. Nem todo teste precisa acontecer no ChatGPT
Testar no ChatGPT é a referência ideal, mas, nas primeiras iterações, um emulador local pode ajudar você a avançar mais rápido, principalmente ao trabalhar em definições de ferramentas que exigem recarregar o aplicativo no Modo de desenvolvedor.
Para acelerar as primeiras iterações, criamos um emulador local leve que simula o ambiente do host do ChatGPT, com ferramentas de depuração e logs específicos dos aplicativos. Isso nos permitiu iterar sobre o estado e o layout no React em milissegundos, reservando os testes no próprio ChatGPT para validar interações com o modelo e casos extremos.
13. Testes em dispositivos móveis exigem suporte específico
Os testes em dispositivos móveis trouxeram outro desafio: embora seja necessário criar um túnel para o servidor local para testar no ChatGPT, o uso de localhost por padrão no Vite torna a mesma URL inacessível em outros dispositivos.
Resolvemos isso ampliando nosso plug-in do Vite para oferecer suporte ao encaminhamento de domínios nas portas acessadas por túnel. Isso viabilizou os testes em dispositivos iOS e Android e tornou a validação em dispositivos móveis parte do nosso fluxo de trabalho habitual.
14. Abstrações conhecidas (como os ganchos do React) aceleram o trabalho no frontend
O Apps SDK oferece recursos poderosos, mas principalmente por meio de APIs JavaScript de baixo nível. Como usamos React há muito tempo, queríamos trabalhar com conceitos mais próximos dos que já dominávamos.
Por isso, introduzimos algumas abstrações adaptadas ao React: ganchos como useCallTool, useWidgetState e useLocale, além de recursos mais avançados de gerenciamento de estado, como createStore, desenvolvido com Zustand para fluxos de dados complexos. Reintroduzir padrões conhecidos de frontend reduziu o código repetitivo e aproximou o desenvolvimento de widgets dos fluxos de trabalho modernos da web.
Transformando lições em uma Habilidade do Codex
15. Transforme lições em ferramentas reutilizáveis
À medida que esses padrões surgiam em vários aplicativos, ficou claro que redescobri-los repetidamente estava nos atrasando. Para tornar o desenvolvimento de Apps do ChatGPT mais rápido e previsível, decidimos incorporar essas lições diretamente às nossas ferramentas, não só para nós, mas também para a comunidade.
Isso levou a duas iniciativas complementares:
- O Skybridge Framework: um framework React de código aberto que reúne muitos dos padrões descritos neste post em blocos reutilizáveis, incluindo nossos ganchos (
useCallTool,useToolInfo), as ferramentas de desenvolvimento (HMR e emulador local) e o atributo data-llm. - A Habilidade do Codex chatgpt-apps-builder: com base no framework, criamos uma Habilidade do Codex dedicada a apoiar todo o ciclo de vida do aplicativo:
- Ideação: explorar ideias para tornar um aplicativo "agêntico", em vez de apenas adaptar uma versão Web.
- Geração de código: escrever simultaneamente o frontend React e o backend do servidor MCP, já configurados com todos os padrões adequados de UX e UI.
- Testes locais: iniciar servidores de desenvolvimento e conectar aplicativos locais ao ChatGPT para iterar em tempo real com recarregamento a quente.
- Garantia de qualidade e publicação: executar verificações estruturadas com base nas diretrizes de envio da OpenAI, incluindo validação de CSP, cuidados com as áreas seguras e testes em produção.
- Implantação do aplicativo: ajudar nas etapas finais necessárias para lançar um aplicativo e continuar iterando.
Para instalar e usar a Habilidade, basta usar o seguinte comando:
npx skills add alpic-ai/skybridge
Conclusão
Criar Apps do ChatGPT exige repensar como o contexto circula, como as interfaces se comportam e como usuários e modelos colaboram. Muitas das lições deste post surgiram das diferenças entre os padrões conhecidos da Web e a realidade dos sistemas agênticos.
Ao compartilhar essas lições e incorporá-las ao nosso framework de código aberto e à nossa habilidade do Codex, esperamos ajudar as equipes a gastar menos tempo redescobrindo os mesmos problemas e mais tempo explorando as possibilidades desse novo modelo de interação. Os Apps do ChatGPT mais interessantes não serão simples adaptações de produtos existentes, mas experiências concebidas intencionalmente em torno dessa nova forma de interação que coloca a IA no centro.