<?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: Preecha</title>
    <description>The latest articles on DEV Community by Preecha (@preecha).</description>
    <link>https://dev.to/preecha</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%2F3891818%2Ffc0ea1ab-a477-4892-93a0-711e6f361ce2.png</url>
      <title>DEV Community: Preecha</title>
      <link>https://dev.to/preecha</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/preecha"/>
    <language>en</language>
    <item>
      <title>Open Source API Management Tools</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Fri, 26 Jun 2026 13:02:58 +0000</pubDate>
      <link>https://dev.to/preecha/open-source-api-management-tools-djh</link>
      <guid>https://dev.to/preecha/open-source-api-management-tools-djh</guid>
      <description>&lt;p&gt;APIs are the backbone of modern applications, but managing them across microservices, mobile apps, partner integrations, and internal platforms gets difficult fast. Open source API management tools give teams a flexible way to secure, publish, monitor, and govern APIs without committing fully to a closed vendor platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;This guide breaks down what open source API management tools do, which features matter, which projects are commonly used in 2026, and how to implement a practical API management workflow from design to runtime governance.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Open Source API Management Tools?
&lt;/h2&gt;

&lt;p&gt;Open source API management tools help teams manage the full API lifecycle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Designing and publishing APIs&lt;/li&gt;
&lt;li&gt;Routing traffic through an API gateway&lt;/li&gt;
&lt;li&gt;Applying authentication and authorization&lt;/li&gt;
&lt;li&gt;Enforcing rate limits and quotas&lt;/li&gt;
&lt;li&gt;Monitoring usage, latency, and errors&lt;/li&gt;
&lt;li&gt;Managing versions, deprecations, and developer access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unlike proprietary API platforms, open source tools provide more transparency and customization. You can inspect the source code, extend behavior with plugins or policies, and adapt the platform to your infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why API Management Matters
&lt;/h2&gt;

&lt;p&gt;As systems scale, APIs often become distributed across teams, regions, and environments. Without API management, common problems include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unauthorized or poorly governed API access&lt;/li&gt;
&lt;li&gt;Inconsistent authentication and rate limiting&lt;/li&gt;
&lt;li&gt;No centralized visibility into API usage&lt;/li&gt;
&lt;li&gt;Difficult API versioning and deprecation&lt;/li&gt;
&lt;li&gt;Scaling issues during traffic spikes&lt;/li&gt;
&lt;li&gt;Vendor lock-in from closed commercial platforms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An API management layer helps standardize how APIs are exposed, secured, monitored, and consumed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Features to Look For
&lt;/h2&gt;

&lt;p&gt;When evaluating open source API management tools, focus on implementation-critical capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. API Gateway
&lt;/h3&gt;

&lt;p&gt;The gateway is the runtime entry point for API traffic. It typically handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request routing&lt;/li&gt;
&lt;li&gt;Load balancing&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Rate limiting&lt;/li&gt;
&lt;li&gt;Protocol handling&lt;/li&gt;
&lt;li&gt;Request and response transformations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example gateway flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client -&amp;gt; API Gateway -&amp;gt; Backend Service
              |
              +-- Auth policy
              +-- Rate limit policy
              +-- Logging policy
              +-- Routing rule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Security and Access Control
&lt;/h3&gt;

&lt;p&gt;Look for support for common API security patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API keys&lt;/li&gt;
&lt;li&gt;OAuth2&lt;/li&gt;
&lt;li&gt;JWT validation&lt;/li&gt;
&lt;li&gt;IP allowlists and blocklists&lt;/li&gt;
&lt;li&gt;mTLS where required&lt;/li&gt;
&lt;li&gt;Role-based or policy-based access control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A basic policy model might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;security&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;authentication&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jwt&lt;/span&gt;
    &lt;span class="na"&gt;issuer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://auth.example.com&lt;/span&gt;
  &lt;span class="na"&gt;access&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;allowed_roles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;partner&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;internal&lt;/span&gt;
  &lt;span class="na"&gt;traffic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;rate_limit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;
      &lt;span class="na"&gt;period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1m&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Traffic Management
&lt;/h3&gt;

&lt;p&gt;Traffic controls protect backend services and create fair usage rules for consumers.&lt;/p&gt;

&lt;p&gt;Common controls include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rate limiting&lt;/li&gt;
&lt;li&gt;Throttling&lt;/li&gt;
&lt;li&gt;Quotas&lt;/li&gt;
&lt;li&gt;Retry rules&lt;/li&gt;
&lt;li&gt;Circuit breaking&lt;/li&gt;
&lt;li&gt;Request size limits&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Analytics and Monitoring
&lt;/h3&gt;

&lt;p&gt;API management tools should help you answer questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which APIs are used most?&lt;/li&gt;
&lt;li&gt;Which consumers generate the most traffic?&lt;/li&gt;
&lt;li&gt;What is the error rate?&lt;/li&gt;
&lt;li&gt;Which endpoints are slow?&lt;/li&gt;
&lt;li&gt;Are there suspicious request patterns?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Useful metrics include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;requests_total
request_latency_ms
error_rate
status_code_distribution
consumer_usage
upstream_response_time
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Developer Portal
&lt;/h3&gt;

&lt;p&gt;A developer portal gives internal or external developers a self-service place to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Discover available APIs&lt;/li&gt;
&lt;li&gt;Read documentation&lt;/li&gt;
&lt;li&gt;Test endpoints&lt;/li&gt;
&lt;li&gt;Request access&lt;/li&gt;
&lt;li&gt;View credentials or subscriptions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is especially useful for partner APIs and API-as-a-product platforms.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. API Lifecycle Management
&lt;/h3&gt;

&lt;p&gt;API management is not only about routing traffic. You also need lifecycle controls for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API design&lt;/li&gt;
&lt;li&gt;Review and approval&lt;/li&gt;
&lt;li&gt;Publishing&lt;/li&gt;
&lt;li&gt;Versioning&lt;/li&gt;
&lt;li&gt;Deprecation&lt;/li&gt;
&lt;li&gt;Retirement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simple lifecycle could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Design -&amp;gt; Review -&amp;gt; Publish -&amp;gt; Monitor -&amp;gt; Version -&amp;gt; Deprecate -&amp;gt; Retire
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7. Extensibility
&lt;/h3&gt;

&lt;p&gt;Open source API management tools often support plugins, custom policies, or scripting.&lt;/p&gt;

&lt;p&gt;Use extensibility when you need to integrate with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Internal identity providers&lt;/li&gt;
&lt;li&gt;Custom logging pipelines&lt;/li&gt;
&lt;li&gt;CI/CD workflows&lt;/li&gt;
&lt;li&gt;Observability platforms&lt;/li&gt;
&lt;li&gt;Compliance systems&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Top Open Source API Management Tools in 2026
&lt;/h2&gt;

&lt;p&gt;The open source API management ecosystem includes several mature options. The right choice depends on your runtime environment, team skills, traffic patterns, and governance requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Kong
&lt;/h2&gt;

&lt;p&gt;Kong is a high-performance API gateway built on NGINX. It is commonly used for scalable API traffic management and has a broad plugin ecosystem.&lt;/p&gt;

&lt;p&gt;Key capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traffic control&lt;/li&gt;
&lt;li&gt;Authentication plugins&lt;/li&gt;
&lt;li&gt;Logging plugins&lt;/li&gt;
&lt;li&gt;Analytics integrations&lt;/li&gt;
&lt;li&gt;Kubernetes-native deployment options&lt;/li&gt;
&lt;li&gt;Declarative configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good fit for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teams running high-traffic APIs&lt;/li&gt;
&lt;li&gt;Kubernetes-based environments&lt;/li&gt;
&lt;li&gt;Plugin-driven gateway customization&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Tyk
&lt;/h2&gt;

&lt;p&gt;Tyk provides an open source gateway with API management features including a dashboard and developer portal options.&lt;/p&gt;

&lt;p&gt;Key capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;REST, GraphQL, and gRPC support&lt;/li&gt;
&lt;li&gt;Fine-grained security controls&lt;/li&gt;
&lt;li&gt;Rate limiting&lt;/li&gt;
&lt;li&gt;API analytics&lt;/li&gt;
&lt;li&gt;Hybrid and multi-cloud deployment support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good fit for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teams that need a lightweight gateway&lt;/li&gt;
&lt;li&gt;Multi-protocol API environments&lt;/li&gt;
&lt;li&gt;Hybrid infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Gravitee.io
&lt;/h2&gt;

&lt;p&gt;Gravitee.io is a modular open source API platform that includes gateway, access management, and developer portal components.&lt;/p&gt;

&lt;p&gt;Key capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Policy-based security&lt;/li&gt;
&lt;li&gt;Traffic shaping&lt;/li&gt;
&lt;li&gt;Analytics&lt;/li&gt;
&lt;li&gt;Developer portal&lt;/li&gt;
&lt;li&gt;Support for event-driven and asynchronous APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good fit for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teams managing both synchronous and asynchronous APIs&lt;/li&gt;
&lt;li&gt;Organizations that need centralized access management&lt;/li&gt;
&lt;li&gt;API platforms with event-driven architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. WSO2 API Manager
&lt;/h2&gt;

&lt;p&gt;WSO2 API Manager is a comprehensive open source API management platform with strong integration and identity management capabilities.&lt;/p&gt;

&lt;p&gt;Key capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API gateway&lt;/li&gt;
&lt;li&gt;API publisher&lt;/li&gt;
&lt;li&gt;API store&lt;/li&gt;
&lt;li&gt;Analytics&lt;/li&gt;
&lt;li&gt;Monetization support&lt;/li&gt;
&lt;li&gt;OAuth2 support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good fit for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enterprise API programs&lt;/li&gt;
&lt;li&gt;Teams needing broader integration capabilities&lt;/li&gt;
&lt;li&gt;Organizations with complex identity requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Apache APISIX
&lt;/h2&gt;

&lt;p&gt;Apache APISIX is a cloud-native API gateway known for dynamic configuration and real-time plugin hot reload.&lt;/p&gt;

&lt;p&gt;Key capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traffic control&lt;/li&gt;
&lt;li&gt;Security policies&lt;/li&gt;
&lt;li&gt;Real-time logging&lt;/li&gt;
&lt;li&gt;Plugin ecosystem&lt;/li&gt;
&lt;li&gt;Support for multiple protocols&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good fit for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cloud-native deployments&lt;/li&gt;
&lt;li&gt;Teams that need dynamic runtime configuration&lt;/li&gt;
&lt;li&gt;High-performance gateway use cases&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. KrakenD
&lt;/h2&gt;

&lt;p&gt;KrakenD is a stateless API gateway focused on aggregation and transformation. It is often used in microservices architectures.&lt;/p&gt;

&lt;p&gt;Key capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Endpoint aggregation&lt;/li&gt;
&lt;li&gt;Request and response transformation&lt;/li&gt;
&lt;li&gt;Security controls&lt;/li&gt;
&lt;li&gt;No-code endpoint configuration&lt;/li&gt;
&lt;li&gt;High-performance stateless design&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good fit for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Backend-for-frontend patterns&lt;/li&gt;
&lt;li&gt;Microservices aggregation&lt;/li&gt;
&lt;li&gt;APIs that need response composition&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. Apiman
&lt;/h2&gt;

&lt;p&gt;Apiman is an extensible open source API management tool focused on policy-based runtime governance.&lt;/p&gt;

&lt;p&gt;Key capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-tenancy&lt;/li&gt;
&lt;li&gt;Metrics&lt;/li&gt;
&lt;li&gt;Custom policies&lt;/li&gt;
&lt;li&gt;Management UI&lt;/li&gt;
&lt;li&gt;Developer portal&lt;/li&gt;
&lt;li&gt;Integration with Java stacks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good fit for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java-based organizations&lt;/li&gt;
&lt;li&gt;Teams needing custom governance policies&lt;/li&gt;
&lt;li&gt;Internal API platforms&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How Open Source API Management Tools Work
&lt;/h2&gt;

&lt;p&gt;Most API management platforms sit between API consumers and backend services.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Web App / Mobile App / Partner App
                |
                v
          API Management Layer
          - Authentication
          - Authorization
          - Rate limiting
          - Routing
          - Logging
          - Analytics
                |
                v
        Backend APIs / Microservices
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A typical workflow looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Design the API&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Define endpoints, methods, parameters, request bodies, responses, and error formats using OpenAPI or Swagger.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Publish the API&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Register the API in your API management platform and expose it through the gateway.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Secure the API&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Apply authentication, authorization, API key, OAuth2, JWT, or IP filtering policies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Control traffic&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Configure rate limits, quotas, throttling, and request validation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monitor usage&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Track requests, errors, latency, and consumer behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Iterate safely&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Version APIs, update documentation, deprecate old endpoints, and retire unused APIs.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Using Apidog Before Runtime API Management
&lt;/h2&gt;

&lt;p&gt;Apidog can complement open source API management tools during the API design, testing, and documentation phase.&lt;/p&gt;

&lt;p&gt;A practical workflow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Design the API contract in Apidog.&lt;/li&gt;
&lt;li&gt;Define endpoints, parameters, request examples, and response examples.&lt;/li&gt;
&lt;li&gt;Generate or maintain OpenAPI/Swagger definitions.&lt;/li&gt;
&lt;li&gt;Share online API documentation with your team.&lt;/li&gt;
&lt;li&gt;Create mock data for frontend or integration testing.&lt;/li&gt;
&lt;li&gt;Export the API specification.&lt;/li&gt;
&lt;li&gt;Import the spec into an API management tool such as Kong, Tyk, Gravitee.io, or Apiman.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This helps ensure APIs are defined and tested before they are exposed through a production gateway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Use Cases
&lt;/h2&gt;

&lt;h2&gt;
  
  
  1. Banking and Fintech
&lt;/h2&gt;

&lt;p&gt;Banks and fintech platforms use API management to expose secure partner APIs for open banking, payment integrations, and regulatory reporting.&lt;/p&gt;

&lt;p&gt;Example implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Tyk Gateway to expose partner APIs.&lt;/li&gt;
&lt;li&gt;Apply OAuth2 policies.&lt;/li&gt;
&lt;li&gt;Enforce rate limits per partner.&lt;/li&gt;
&lt;li&gt;Log API activity for audit and compliance.&lt;/li&gt;
&lt;li&gt;Monitor failed authentication attempts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. E-commerce Platforms
&lt;/h2&gt;

&lt;p&gt;E-commerce companies use API management to scale APIs for storefronts, mobile apps, vendors, and logistics partners.&lt;/p&gt;

&lt;p&gt;Example implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Kong as the API gateway.&lt;/li&gt;
&lt;li&gt;Route traffic to catalog, cart, checkout, and logistics services.&lt;/li&gt;
&lt;li&gt;Apply rate limits to public APIs.&lt;/li&gt;
&lt;li&gt;Track request volume and latency.&lt;/li&gt;
&lt;li&gt;Use analytics to identify slow or error-prone endpoints.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Healthcare and IoT
&lt;/h2&gt;

&lt;p&gt;Healthcare and IoT systems often need strict access control and audit logging for sensitive data APIs.&lt;/p&gt;

&lt;p&gt;Example implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Gravitee.io to expose FHIR APIs.&lt;/li&gt;
&lt;li&gt;Apply access policies for healthcare apps.&lt;/li&gt;
&lt;li&gt;Monitor unusual request patterns.&lt;/li&gt;
&lt;li&gt;Centralize audit logs.&lt;/li&gt;
&lt;li&gt;Enforce security controls for patient data APIs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. SaaS and Developer Platforms
&lt;/h2&gt;

&lt;p&gt;Developer-focused SaaS companies use API management to provide self-service onboarding, documentation, and sandbox environments.&lt;/p&gt;

&lt;p&gt;Example implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Apidog for API design, testing, and documentation.&lt;/li&gt;
&lt;li&gt;Use Apiman for runtime governance.&lt;/li&gt;
&lt;li&gt;Publish APIs through a developer portal.&lt;/li&gt;
&lt;li&gt;Apply subscription-based access policies.&lt;/li&gt;
&lt;li&gt;Monitor usage by developer account or tenant.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Practical Implementation Workflow
&lt;/h2&gt;

&lt;p&gt;Here is a practical implementation path for combining API design tooling with open source API management.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Design the API Contract
&lt;/h2&gt;

&lt;p&gt;Start with an API specification.&lt;/p&gt;

&lt;p&gt;Example OpenAPI fragment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;openapi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3.0.3&lt;/span&gt;
&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Orders API&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.0.0&lt;/span&gt;
&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;/orders&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;List orders&lt;/span&gt;
      &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;200"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;A list of orders&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;array&lt;/span&gt;
                &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
                  &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
                    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use Apidog to define endpoints, parameters, examples, and responses before exporting the OpenAPI or Swagger file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Export the OpenAPI or Swagger Spec
&lt;/h2&gt;

&lt;p&gt;Export the API contract from your design tool.&lt;/p&gt;

&lt;p&gt;Example file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apidog-exported-api.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep this file versioned in Git so API changes can go through review.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add apidog-exported-api.json
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add Orders API specification"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Import the API into Your Management Tool
&lt;/h2&gt;

&lt;p&gt;Import the exported API definition into your API management platform.&lt;/p&gt;

&lt;p&gt;Example: importing a Swagger/OpenAPI spec into Apiman:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; @apidog-exported-api.json &lt;span class="se"&gt;\&lt;/span&gt;
  https://&lt;span class="o"&gt;{&lt;/span&gt;apiman-server&lt;span class="o"&gt;}&lt;/span&gt;/apiman/rest/apis/import
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;{apiman-server}&lt;/code&gt; with your Apiman server hostname.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Configure Runtime Policies
&lt;/h2&gt;

&lt;p&gt;After importing the API, configure policies such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Authorization&lt;/li&gt;
&lt;li&gt;Rate limiting&lt;/li&gt;
&lt;li&gt;Request validation&lt;/li&gt;
&lt;li&gt;Logging&lt;/li&gt;
&lt;li&gt;CORS&lt;/li&gt;
&lt;li&gt;Quotas&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example policy checklist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] Require authentication
[ ] Validate JWT issuer
[ ] Apply per-consumer rate limit
[ ] Enable request logging
[ ] Track 4xx and 5xx errors
[ ] Add versioning rules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Publish Through the Gateway
&lt;/h2&gt;

&lt;p&gt;Expose the API through your gateway endpoint.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://api.example.com/orders
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Route requests to the backend service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://orders-service.internal/orders
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Monitor and Iterate
&lt;/h2&gt;

&lt;p&gt;Track operational metrics after release:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request count&lt;/li&gt;
&lt;li&gt;Error rate&lt;/li&gt;
&lt;li&gt;Latency&lt;/li&gt;
&lt;li&gt;Top consumers&lt;/li&gt;
&lt;li&gt;Rate limit violations&lt;/li&gt;
&lt;li&gt;Authentication failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use these signals to decide when to optimize, scale, version, or deprecate endpoints.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of Open Source API Management Tools
&lt;/h2&gt;

&lt;p&gt;Open source API management tools offer several practical benefits.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Advantage&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cost savings&lt;/td&gt;
&lt;td&gt;No licensing fees for the open source components&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transparency&lt;/td&gt;
&lt;td&gt;Source code can be reviewed for security and compliance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customization&lt;/td&gt;
&lt;td&gt;Policies, plugins, and integrations can be adapted to your stack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Community support&lt;/td&gt;
&lt;td&gt;Active communities help with troubleshooting and improvements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reduced vendor lock-in&lt;/td&gt;
&lt;td&gt;Teams can migrate, fork, or extend tools as requirements change&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Challenges and Considerations
&lt;/h2&gt;

&lt;p&gt;Open source API management is powerful, but it still requires operational planning.&lt;/p&gt;

&lt;h3&gt;
  
  
  Operational Overhead
&lt;/h3&gt;

&lt;p&gt;You need in-house expertise to deploy, secure, scale, upgrade, and monitor the platform.&lt;/p&gt;

&lt;p&gt;Plan for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High availability&lt;/li&gt;
&lt;li&gt;Backups&lt;/li&gt;
&lt;li&gt;Configuration management&lt;/li&gt;
&lt;li&gt;Gateway scaling&lt;/li&gt;
&lt;li&gt;Observability&lt;/li&gt;
&lt;li&gt;Security patching&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Feature Gaps
&lt;/h3&gt;

&lt;p&gt;Some advanced capabilities may require commercial editions, plugins, or custom implementation.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Advanced monetization&lt;/li&gt;
&lt;li&gt;AI-based analytics&lt;/li&gt;
&lt;li&gt;Enterprise support&lt;/li&gt;
&lt;li&gt;Advanced developer portal features&lt;/li&gt;
&lt;li&gt;Managed hosting&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Integration Complexity
&lt;/h3&gt;

&lt;p&gt;Before choosing a tool, validate compatibility with your existing stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CI/CD pipelines&lt;/li&gt;
&lt;li&gt;Identity providers&lt;/li&gt;
&lt;li&gt;Logging systems&lt;/li&gt;
&lt;li&gt;Metrics platforms&lt;/li&gt;
&lt;li&gt;Kubernetes or VM infrastructure&lt;/li&gt;
&lt;li&gt;Secrets management&lt;/li&gt;
&lt;li&gt;API documentation workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation Checklist
&lt;/h2&gt;

&lt;p&gt;Use this checklist before adopting an open source API management platform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] Identify APIs that need centralized management
[ ] Define authentication and authorization requirements
[ ] Choose gateway deployment model
[ ] Decide how API specs will be created and versioned
[ ] Configure logging and monitoring
[ ] Define rate limits and quotas
[ ] Set up developer onboarding flow
[ ] Test failure scenarios
[ ] Document API publishing process
[ ] Create versioning and deprecation rules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Open source API management tools help teams secure, govern, publish, and monitor APIs with more flexibility and transparency. Tools like Kong, Tyk, Gravitee.io, WSO2 API Manager, Apache APISIX, KrakenD, and Apiman can provide the runtime control layer for modern API platforms.&lt;/p&gt;

&lt;p&gt;For a practical implementation, separate API design from runtime governance:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Design and test the API contract.&lt;/li&gt;
&lt;li&gt;Export an OpenAPI or Swagger specification.&lt;/li&gt;
&lt;li&gt;Import it into your API management platform.&lt;/li&gt;
&lt;li&gt;Apply security and traffic policies.&lt;/li&gt;
&lt;li&gt;Monitor usage and iterate over time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Combining open source API management tools with an API design and documentation workflow helps teams ship APIs that are easier to secure, operate, and evolve.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Hermes Agent: The Better OpenClaw Alternative Is Here</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Fri, 26 Jun 2026 01:02:51 +0000</pubDate>
      <link>https://dev.to/preecha/hermes-agent-the-better-openclaw-alternative-is-here-1a21</link>
      <guid>https://dev.to/preecha/hermes-agent-the-better-openclaw-alternative-is-here-1a21</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR / Quick Answer
&lt;/h2&gt;

&lt;p&gt;For API-heavy workflows, Hermes Agent is the stronger OpenClaw alternative for most teams. It combines official MCP support, broader provider flexibility, built-in OpenClaw migration, self-improving skills, and more deployment options. OpenClaw still makes sense if you prefer a gateway-first runtime, a tightly scoped workspace model, and its existing plugin and cron setup.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If you are evaluating Hermes Agent as an OpenClaw alternative, the short answer is yes for many developer-facing API workflows. The reason is not hype. It is stack coverage.&lt;/p&gt;

&lt;p&gt;Hermes Agent is positioned as a self-improving agent with MCP support, multiple messaging surfaces, scheduled automations, provider choice, and an official &lt;code&gt;hermes claw migrate&lt;/code&gt; path for OpenClaw users.&lt;/p&gt;

&lt;p&gt;OpenClaw is still a capable runtime. Its docs describe a gateway scheduler, custom skills, plugins, and a clear workspace model. The practical decision is not “which agent is newer?” It is “which runtime fits the way your team connects APIs, tools, webhooks, and MCP servers?”&lt;/p&gt;

&lt;p&gt;That is also where &lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=blog-sync"&gt;Apidog&lt;/a&gt; fits. If you are building the API contracts either agent will call, Apidog helps you design, mock, test, and document those integrations before an agent touches production data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Hermes Agent?
&lt;/h2&gt;

&lt;p&gt;Hermes Agent is an open-source AI assistant from NousResearch. It is designed to retain context, learn from past sessions, and become more useful over time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9uue7jiwv8gve6mpj31.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9uue7jiwv8gve6mpj31.png" alt="Image" width="800" height="137"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unlike a stateless assistant that starts from zero each session, Hermes builds persistent context around projects, preferences, and workflow patterns.&lt;/p&gt;

&lt;p&gt;Its main differentiator is the learning loop:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Conversations and completed tasks can feed future behavior.&lt;/li&gt;
&lt;li&gt;Repeated workflows can become reusable skills.&lt;/li&gt;
&lt;li&gt;Past sessions can be searched for relevant context.&lt;/li&gt;
&lt;li&gt;Project-specific preferences can persist across runs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For developers, that matters when the agent is not just answering questions but repeatedly working with codebases, APIs, internal tools, and operational workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Developers Compare Hermes Agent and OpenClaw
&lt;/h2&gt;

&lt;p&gt;Hermes and OpenClaw target overlapping use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CLI-based agent workflows&lt;/li&gt;
&lt;li&gt;Long-lived project context&lt;/li&gt;
&lt;li&gt;Skills or reusable workflows&lt;/li&gt;
&lt;li&gt;Scheduled automation&lt;/li&gt;
&lt;li&gt;Tool integration&lt;/li&gt;
&lt;li&gt;Messaging or gateway-style interaction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But their public positioning is different.&lt;/p&gt;

&lt;p&gt;Hermes presents itself as a broader agent platform with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;built-in learning loop&lt;/li&gt;
&lt;li&gt;cross-session memory&lt;/li&gt;
&lt;li&gt;skills&lt;/li&gt;
&lt;li&gt;scheduled automations&lt;/li&gt;
&lt;li&gt;parallel delegation&lt;/li&gt;
&lt;li&gt;MCP support&lt;/li&gt;
&lt;li&gt;OpenClaw migration tooling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OpenClaw is framed more as a gateway-centered runtime with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a single workspace model&lt;/li&gt;
&lt;li&gt;bootstrap files such as &lt;code&gt;AGENTS.md&lt;/code&gt; and &lt;code&gt;SOUL.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;openclaw cron&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;WebSocket gateway&lt;/li&gt;
&lt;li&gt;custom skills&lt;/li&gt;
&lt;li&gt;plugin extension points&lt;/li&gt;
&lt;li&gt;context-engine plugins&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That difference changes implementation choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose Hermes when you want more of the agent stack pre-integrated.&lt;/li&gt;
&lt;li&gt;Choose OpenClaw when you want a focused runtime around an existing workspace and gateway setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For API work, this distinction matters because the agent is only one layer. The difficult parts are usually underneath it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP APIs&lt;/li&gt;
&lt;li&gt;MCP servers&lt;/li&gt;
&lt;li&gt;webhooks&lt;/li&gt;
&lt;li&gt;secrets&lt;/li&gt;
&lt;li&gt;approval policies&lt;/li&gt;
&lt;li&gt;test environments&lt;/li&gt;
&lt;li&gt;documentation&lt;/li&gt;
&lt;li&gt;schema drift&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Core Product Differences
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Hermes Agent&lt;/th&gt;
&lt;th&gt;OpenClaw&lt;/th&gt;
&lt;th&gt;Why it matters for API workflows&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Memory model&lt;/td&gt;
&lt;td&gt;Built-in learning loop, skill creation, session search, user modeling&lt;/td&gt;
&lt;td&gt;Workspace context, runtime memory model, bootstrap files&lt;/td&gt;
&lt;td&gt;Hermes does more out of the box for long-running operational knowledge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool extension&lt;/td&gt;
&lt;td&gt;Skills plus official MCP support&lt;/td&gt;
&lt;td&gt;Skills plus plugins and plugin slots&lt;/td&gt;
&lt;td&gt;Hermes is easier if your tools already exist as MCP servers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime shape&lt;/td&gt;
&lt;td&gt;CLI, gateway, multiple terminal backends, scheduled automations&lt;/td&gt;
&lt;td&gt;Embedded runtime centered around workspace and gateway&lt;/td&gt;
&lt;td&gt;Hermes is easier to stretch across local, VPS, and remote environments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Migration&lt;/td&gt;
&lt;td&gt;Official &lt;code&gt;hermes claw migrate&lt;/code&gt; flow&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;Hermes lowers switching cost for OpenClaw users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Provider surface&lt;/td&gt;
&lt;td&gt;Nous Portal, OpenRouter, OpenAI, Anthropic, GitHub Copilot, local endpoints, and more&lt;/td&gt;
&lt;td&gt;Model options exist, but public positioning is less expansive&lt;/td&gt;
&lt;td&gt;Hermes is easier to match to team budget and provider constraints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Project context&lt;/td&gt;
&lt;td&gt;Context files and project-level instructions&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;AGENTS.md&lt;/code&gt;, &lt;code&gt;SOUL.md&lt;/code&gt;, &lt;code&gt;TOOLS.md&lt;/code&gt;, &lt;code&gt;BOOTSTRAP.md&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Both are workable; Hermes aims for broader operational context&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The important point: OpenClaw still has substance. Its docs cover cron jobs, plugins, gateway configuration, and custom skills.&lt;/p&gt;

&lt;p&gt;Hermes adds a more complete stack around those same categories, especially for teams that want MCP, migration, provider flexibility, and multi-surface automation in one path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hermes vs OpenClaw: Feature Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Hermes Agent&lt;/th&gt;
&lt;th&gt;OpenClaw&lt;/th&gt;
&lt;th&gt;Practical takeaway&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenClaw migration&lt;/td&gt;
&lt;td&gt;Yes, via &lt;code&gt;hermes claw migrate&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;Hermes makes switching realistic instead of theoretical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP support&lt;/td&gt;
&lt;td&gt;Official docs and config path&lt;/td&gt;
&lt;td&gt;Not the main public extension story&lt;/td&gt;
&lt;td&gt;Hermes is easier if your tool layer is MCP-based&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Messaging surfaces&lt;/td&gt;
&lt;td&gt;Broad multi-surface story across CLI and messaging&lt;/td&gt;
&lt;td&gt;Gateway-first runtime with messaging workflows&lt;/td&gt;
&lt;td&gt;Both can work; Hermes packages more of the setup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scheduling&lt;/td&gt;
&lt;td&gt;Built-in scheduled automations&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;openclaw cron&lt;/code&gt; scheduler&lt;/td&gt;
&lt;td&gt;Both support scheduled workflows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skills&lt;/td&gt;
&lt;td&gt;Self-improving skill loop&lt;/td&gt;
&lt;td&gt;Custom skills&lt;/td&gt;
&lt;td&gt;Hermes emphasizes automatic skill evolution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plugins&lt;/td&gt;
&lt;td&gt;Multiple extension paths&lt;/td&gt;
&lt;td&gt;Plugin and context-engine plugin model&lt;/td&gt;
&lt;td&gt;OpenClaw still has serious extension points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Provider flexibility&lt;/td&gt;
&lt;td&gt;Wider public provider story&lt;/td&gt;
&lt;td&gt;Less central in public docs&lt;/td&gt;
&lt;td&gt;Hermes is easier to adapt to cost or provider changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment options&lt;/td&gt;
&lt;td&gt;Local plus broader backend and VPS-friendly options&lt;/td&gt;
&lt;td&gt;Tighter runtime and workspace model&lt;/td&gt;
&lt;td&gt;Hermes fits more operations use cases&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Migration Guide: OpenClaw to Hermes
&lt;/h2&gt;

&lt;p&gt;If you already use OpenClaw, start with a dry run.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes claw migrate &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the output to review what Hermes can import before changing your active setup.&lt;/p&gt;

&lt;p&gt;Then run the migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes claw migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Based on the public Hermes migration docs and README, the migration path is designed to bring over operational state such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;memories and user context&lt;/li&gt;
&lt;li&gt;existing skills&lt;/li&gt;
&lt;li&gt;command approval patterns&lt;/li&gt;
&lt;li&gt;messaging settings&lt;/li&gt;
&lt;li&gt;some workspace-level instructions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A safer migration sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install Hermes.&lt;/li&gt;
&lt;li&gt;Run the health check.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   hermes doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Run the migration dry run.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   hermes claw migrate &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Review imported skills, messaging settings, and command approvals.&lt;/li&gt;
&lt;li&gt;Run the full migration.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   hermes claw migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Start with a CLI-only session.&lt;/li&gt;
&lt;li&gt;Reconnect messaging surfaces after the base runtime works.&lt;/li&gt;
&lt;li&gt;Re-add MCP servers or external tool integrations last.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That order isolates failures. If something breaks, you can tell whether the cause is imported state, provider configuration, or a new integration.&lt;/p&gt;

&lt;p&gt;If your OpenClaw setup depends on custom plugins or strict workspace bootstrap files, treat migration like a runtime change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;export important state&lt;/li&gt;
&lt;li&gt;test one workflow at a time&lt;/li&gt;
&lt;li&gt;validate API-backed tools before handing them to the agent&lt;/li&gt;
&lt;li&gt;keep rollback instructions available&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For API-backed workflows, validate the contract in &lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=blog-sync"&gt;Apidog&lt;/a&gt; first. Otherwise, you may blame the agent for an unstable integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Standout Hermes Features
&lt;/h2&gt;

&lt;p&gt;Hermes stands out where it combines capabilities that OpenClaw does not present as its main path today.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. First-class OpenClaw migration
&lt;/h3&gt;

&lt;p&gt;Hermes directly acknowledges OpenClaw users with a migration command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes claw migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That lowers switching cost compared with manually recreating skills, memory, approvals, and messaging settings.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Official MCP-based expansion
&lt;/h3&gt;

&lt;p&gt;OpenClaw supports plugins and skills. Hermes adds an official MCP configuration path.&lt;/p&gt;

&lt;p&gt;That matters if your team is already exposing tools through MCP servers, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;filesystem access&lt;/li&gt;
&lt;li&gt;GitHub operations&lt;/li&gt;
&lt;li&gt;database tools&lt;/li&gt;
&lt;li&gt;fetch tools&lt;/li&gt;
&lt;li&gt;internal service wrappers&lt;/li&gt;
&lt;li&gt;custom operational APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Broader provider and backend surface
&lt;/h3&gt;

&lt;p&gt;Hermes is more explicit about provider choice and runtime backends.&lt;/p&gt;

&lt;p&gt;That helps when you need to change model vendors, run locally, use a VPS, or connect through remote execution environments without redesigning the whole workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Stronger learning-loop model
&lt;/h3&gt;

&lt;p&gt;Both tools care about persistent usefulness, but Hermes makes self-improving skills, user modeling, and cross-session recall central to the product.&lt;/p&gt;

&lt;p&gt;For recurring API operations, that can reduce repeated prompting and manual setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Better fit for API-plus-messaging workflows
&lt;/h3&gt;

&lt;p&gt;Hermes combines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;migration support&lt;/li&gt;
&lt;li&gt;MCP&lt;/li&gt;
&lt;li&gt;provider flexibility&lt;/li&gt;
&lt;li&gt;messaging&lt;/li&gt;
&lt;li&gt;scheduling&lt;/li&gt;
&lt;li&gt;broader deployment options&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That combination is why it feels more complete for API operations, not just more feature-heavy on paper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which One Is Better for API Workflows?
&lt;/h2&gt;

&lt;p&gt;For most teams building against internal APIs, webhooks, or MCP-connected services, Hermes is the stronger default.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Hermes has a cleaner path to external tool ecosystems
&lt;/h3&gt;

&lt;p&gt;Hermes has official MCP documentation and example configuration for local and remote MCP servers.&lt;/p&gt;

&lt;p&gt;A typical Hermes MCP configuration looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;mcp_servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;filesystem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;npx"&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-y"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@modelcontextprotocol/server-filesystem"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/home/user/projects"&lt;/span&gt;

  &lt;span class="na"&gt;github&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;npx"&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-y"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@modelcontextprotocol/server-github"&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;GITHUB_PERSONAL_ACCESS_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${GITHUB_PERSONAL_ACCESS_TOKEN}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That fits teams that already think in service boundaries and tool contracts.&lt;/p&gt;

&lt;p&gt;If your engineering org exposes capabilities through MCP, Hermes maps cleanly to that model.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Hermes has the stronger migration story
&lt;/h3&gt;

&lt;p&gt;The migration command makes the OpenClaw comparison practical instead of theoretical.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes claw migrate &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
hermes claw migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you already use OpenClaw, this is the first feature to test.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Hermes is broader without forcing a browser-first workflow
&lt;/h3&gt;

&lt;p&gt;Hermes can run in the CLI, but it is not limited to the CLI. Its docs also describe messaging surfaces such as Telegram and WhatsApp, plus scheduled job output.&lt;/p&gt;

&lt;p&gt;That is useful for operational tasks like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;posting nightly API audit summaries&lt;/li&gt;
&lt;li&gt;sending deployment health checks&lt;/li&gt;
&lt;li&gt;surfacing failed contract tests&lt;/li&gt;
&lt;li&gt;summarizing queue backlogs&lt;/li&gt;
&lt;li&gt;reporting webhook failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OpenClaw can handle scheduled gateway work too. Its cron docs show scheduler behavior such as retention, retries, and job history.&lt;/p&gt;

&lt;p&gt;The difference is that Hermes presents more of the full path together: model selection, tools, messaging, cron, provider setup, and migration.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Hermes is better aligned with provider churn
&lt;/h3&gt;

&lt;p&gt;API-heavy agent workflows can break or become expensive when model providers change pricing, rate limits, or behavior.&lt;/p&gt;

&lt;p&gt;Hermes emphasizes provider flexibility, including OpenRouter, OpenAI-compatible endpoints, and multiple direct integrations.&lt;/p&gt;

&lt;p&gt;That flexibility is useful if your team does not want agent architecture tied to one model vendor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where OpenClaw Still Makes Sense
&lt;/h2&gt;

&lt;p&gt;OpenClaw should not be dismissed.&lt;/p&gt;

&lt;p&gt;Its current docs still describe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;clear agent runtime model&lt;/li&gt;
&lt;li&gt;dedicated workspace abstraction&lt;/li&gt;
&lt;li&gt;bootstrap context files&lt;/li&gt;
&lt;li&gt;custom skills&lt;/li&gt;
&lt;li&gt;plugin support&lt;/li&gt;
&lt;li&gt;context-engine plugins&lt;/li&gt;
&lt;li&gt;gateway scheduling via &lt;code&gt;openclaw cron&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OpenClaw remains a good option if you value:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a simpler workspace model&lt;/li&gt;
&lt;li&gt;gateway-first workflows&lt;/li&gt;
&lt;li&gt;existing skills or plugins your team depends on&lt;/li&gt;
&lt;li&gt;avoiding migration work&lt;/li&gt;
&lt;li&gt;predictable workspace policy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OpenClaw can also be easier to treat as a contained runtime with a known home directory and workspace structure.&lt;/p&gt;

&lt;p&gt;A better framing is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hermes is the better default for API-heavy, MCP-based, multi-surface automation.&lt;/li&gt;
&lt;li&gt;OpenClaw is still valid if your current runtime and plugin model already work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How Apidog Fits Into Either Stack
&lt;/h2&gt;

&lt;p&gt;Hermes and OpenClaw are agent layers. Apidog is the API contract layer beneath them.&lt;/p&gt;

&lt;p&gt;The fragile part of an agent workflow is usually not the chat interface. It is the service interface.&lt;/p&gt;

&lt;p&gt;If the agent calls an unclear webhook, a drifting OpenAPI schema, or an undocumented status model, the workflow becomes unreliable.&lt;/p&gt;

&lt;p&gt;A practical stack looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Apidog -&amp;gt; define and test the API contract
MCP server or plugin -&amp;gt; expose that contract to the agent
Hermes Agent or OpenClaw -&amp;gt; call the tool in a workflow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example: your team wants an agent that triggers an internal API audit and posts the result in Telegram.&lt;/p&gt;

&lt;p&gt;Define the HTTP contract first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /audits
GET /audits/{audit_id}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set up an environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;base_url = https://internal-api.example.com
token = redacted
audit_id =
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add assertions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;POST /audits&lt;/code&gt; returns &lt;code&gt;202&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;response includes &lt;code&gt;audit_id&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /audits/{audit_id}&lt;/code&gt; moves from &lt;code&gt;queued&lt;/code&gt; to &lt;code&gt;completed&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;failure states are documented&lt;/li&gt;
&lt;li&gt;auth errors return predictable status codes&lt;/li&gt;
&lt;li&gt;retry behavior is clear&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only after the contract is stable should you expose it to the agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hermes via MCP or another compatible tool path&lt;/li&gt;
&lt;li&gt;OpenClaw via plugin, skill, or gateway workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This prevents a common failure mode: blaming the agent for a weak API contract.&lt;/p&gt;

&lt;p&gt;Use &lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=blog-sync"&gt;Apidog&lt;/a&gt; to design, test, and document the APIs your Hermes Agent or OpenClaw workflows rely on before those integrations go live.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Evaluation Checklist
&lt;/h2&gt;

&lt;p&gt;Do not choose based only on “which one writes better replies.”&lt;/p&gt;

&lt;p&gt;Use this checklist instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. How does the tool handle context pressure?
&lt;/h3&gt;

&lt;p&gt;Hermes emphasizes compression, session search, and persistent knowledge.&lt;/p&gt;

&lt;p&gt;OpenClaw also has a context engine model and plugin hooks.&lt;/p&gt;

&lt;p&gt;If your workflows run for days or weeks, context management matters more than demo quality.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. How much of your tool layer already exists as APIs or MCP servers?
&lt;/h3&gt;

&lt;p&gt;If much of your tooling is already API-backed or MCP-ready, Hermes has the simpler story today.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. How hard is it to move existing operational state?
&lt;/h3&gt;

&lt;p&gt;If you are already on OpenClaw, test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes claw migrate &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The migration path is one of Hermes’ strongest practical advantages.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. How much deployment flexibility do you need?
&lt;/h3&gt;

&lt;p&gt;Hermes is explicit about local, Docker, SSH, Modal, and other backend options.&lt;/p&gt;

&lt;p&gt;That matters if you want the agent to run on a VPS, connect to remote systems, or wake up only for scheduled jobs.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Do you need a platform or a runtime?
&lt;/h3&gt;

&lt;p&gt;Use this as the final decision line:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Choose Hermes if you want a broader agent platform.&lt;/li&gt;
&lt;li&gt;Stay with OpenClaw if you want a tighter runtime and your current setup already works.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Alternatives and Comparisons
&lt;/h2&gt;

&lt;p&gt;If your main goal is coding assistance, Hermes and OpenClaw are not the only options.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Best fit&lt;/th&gt;
&lt;th&gt;Where it differs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hermes Agent&lt;/td&gt;
&lt;td&gt;API-heavy personal or team agent workflows&lt;/td&gt;
&lt;td&gt;Broader stack with MCP, messaging, automation, and migration path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenClaw&lt;/td&gt;
&lt;td&gt;Gateway-first agent runtime with existing plugin or skill investment&lt;/td&gt;
&lt;td&gt;More focused workspace model and runtime-centered design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code&lt;/td&gt;
&lt;td&gt;Code-first terminal agent&lt;/td&gt;
&lt;td&gt;Strong for coding, weaker as a messaging-first personal agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codex-style agents&lt;/td&gt;
&lt;td&gt;Repo work, automation, code change execution&lt;/td&gt;
&lt;td&gt;Good for engineering tasks, not the same long-lived messaging agent model&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Hermes is the closer OpenClaw alternative because it competes at the same architectural layer: long-lived agent runtime plus tools, scheduling, and integrations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Use Cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Internal API operations assistant
&lt;/h3&gt;

&lt;p&gt;You want a bot that can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;summarize failed contract tests&lt;/li&gt;
&lt;li&gt;create follow-up tickets&lt;/li&gt;
&lt;li&gt;post a digest to Telegram&lt;/li&gt;
&lt;li&gt;rerun checks after fixes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hermes is a better fit if you also want MCP-based tool growth and scheduled delivery.&lt;/p&gt;

&lt;p&gt;OpenClaw is still viable if your gateway flow already exists.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Team knowledge and workflow agent
&lt;/h3&gt;

&lt;p&gt;You want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;project instructions&lt;/li&gt;
&lt;li&gt;reusable skills&lt;/li&gt;
&lt;li&gt;cross-session recall&lt;/li&gt;
&lt;li&gt;workflow memory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hermes has the stronger public story here because the learning loop is central to the product.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. API watchdog on a cheap VPS
&lt;/h3&gt;

&lt;p&gt;You want a small always-on agent that watches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;logs&lt;/li&gt;
&lt;li&gt;health checks&lt;/li&gt;
&lt;li&gt;webhook activity&lt;/li&gt;
&lt;li&gt;failed jobs&lt;/li&gt;
&lt;li&gt;API contract test results&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hermes is easier to recommend because its docs describe VPS-friendly and remote backend setups.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Hermes Agent is the better OpenClaw alternative for most API-heavy workflows right now.&lt;/p&gt;

&lt;p&gt;OpenClaw still has a credible runtime, scheduler, skills system, and plugin model. If your team already built around OpenClaw and it works, there may be no urgent reason to migrate.&lt;/p&gt;

&lt;p&gt;The biggest Hermes advantage is not one feature. It is how much of the modern agent stack is already connected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MCP&lt;/li&gt;
&lt;li&gt;migration&lt;/li&gt;
&lt;li&gt;scheduling&lt;/li&gt;
&lt;li&gt;messaging&lt;/li&gt;
&lt;li&gt;provider flexibility&lt;/li&gt;
&lt;li&gt;persistent learning&lt;/li&gt;
&lt;li&gt;broader deployment paths&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The biggest OpenClaw advantage is simplicity for teams already aligned with its workspace and gateway model.&lt;/p&gt;

&lt;p&gt;If you are starting fresh, Hermes is the better default. If you are already on OpenClaw, test the migration path before rebuilding anything manually. And if your real problem is unstable API contracts, fix that first in &lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=blog-sync"&gt;Apidog&lt;/a&gt; so the agent layer has reliable tools to call.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is “Hermers Agent” the same as Hermes Agent?
&lt;/h3&gt;

&lt;p&gt;Yes. People sometimes type “Hermers Agent,” but the project is Hermes Agent by NousResearch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Hermes Agent connected to OpenClaw?
&lt;/h3&gt;

&lt;p&gt;They are separate projects today, but Hermes explicitly supports migration from OpenClaw. That is why the comparison appears often.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does OpenClaw still support plugins and cron jobs?
&lt;/h3&gt;

&lt;p&gt;Yes. OpenClaw’s current docs describe a plugin system, context-engine plugins, custom skills, and scheduler commands under &lt;code&gt;openclaw cron&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why is Hermes better for API-heavy workflows?
&lt;/h3&gt;

&lt;p&gt;Because Hermes combines broader provider support, official MCP documentation, migration tooling, scheduling, messaging, and a stronger learning-loop story in one stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can Hermes Agent replace Apidog?
&lt;/h3&gt;

&lt;p&gt;No. Hermes is an agent. Apidog is for API design, testing, mocking, environments, and documentation. They solve different layers of the same workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Hermes Agent run on native Windows?
&lt;/h3&gt;

&lt;p&gt;No. The official install docs say Linux, macOS, and WSL2 are supported, while native Windows is not.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Use Hermes Agent</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Thu, 25 Jun 2026 13:03:32 +0000</pubDate>
      <link>https://dev.to/preecha/how-to-use-hermes-agent-5ch7</link>
      <guid>https://dev.to/preecha/how-to-use-hermes-agent-5ch7</guid>
      <description>&lt;p&gt;TL;DR: Hermes Agent is an open-source AI assistant that keeps persistent memory across sessions, learns reusable skills, and can run through CLI, Telegram, Discord, Slack, your IDE, or scheduled automation. This guide walks through installation, configuration, daily usage, integrations, memory, skills, and troubleshooting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Hermes Agent?
&lt;/h2&gt;

&lt;p&gt;Hermes Agent is a personal AI assistant from NousResearch that can run continuously, remember prior work, and improve over time. Unlike tools that start each conversation from scratch, Hermes builds persistent context around your projects, preferences, conversations, and workflows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbn7xyr7n0ho03doa7j0i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbn7xyr7n0ho03doa7j0i.png" alt="Image" width="800" height="137"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Core capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Persistent memory&lt;/strong&gt;: stores conversations, decisions, and code context&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learning system&lt;/strong&gt;: turns repeated tasks into reusable skills&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-platform access&lt;/strong&gt;: CLI, Telegram, Discord, Slack, WhatsApp, and IDE workflows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-hosting&lt;/strong&gt;: run locally, on a VPS, or in cloud infrastructure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model flexibility&lt;/strong&gt;: use OpenRouter or direct LLM providers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensibility&lt;/strong&gt;: add plugins, tools, commands, and hooks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hermes is useful if you want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An AI pair programmer that can remember your codebase&lt;/li&gt;
&lt;li&gt;A shared assistant for a team or workspace&lt;/li&gt;
&lt;li&gt;Long-running automation through scheduled tasks&lt;/li&gt;
&lt;li&gt;Data for training or evaluating custom agent behavior&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before installing Hermes, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;macOS, Linux, or Windows with WSL recommended&lt;/li&gt;
&lt;li&gt;Python 3.10+&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;li&gt;An API key from OpenRouter, Anthropic, OpenAI, or another supported provider&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Quick Install
&lt;/h3&gt;

&lt;p&gt;Use the installer script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clones the Hermes repository&lt;/li&gt;
&lt;li&gt;Installs &lt;code&gt;uv&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Creates a Python virtual environment&lt;/li&gt;
&lt;li&gt;Installs dependencies&lt;/li&gt;
&lt;li&gt;Adds Hermes to your &lt;code&gt;PATH&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Reload your shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc  &lt;span class="c"&gt;# bash&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.zshrc   &lt;span class="c"&gt;# zsh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see output similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hermes Agent v0.5.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Manual Install
&lt;/h3&gt;

&lt;p&gt;Use this path if you want to work on Hermes directly or control the environment yourself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/NousResearch/hermes-agent.git
&lt;span class="nb"&gt;cd &lt;/span&gt;hermes-agent

curl &lt;span class="nt"&gt;-LsSf&lt;/span&gt; https://astral.sh/uv/install.sh | sh

uv venv venv &lt;span class="nt"&gt;--python&lt;/span&gt; 3.11
&lt;span class="nb"&gt;source &lt;/span&gt;venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;\venv\Scripts\activate&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install Hermes with all features:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;".[all,dev]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; pytest tests/ &lt;span class="nt"&gt;-q&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Install RL Training Support
&lt;/h3&gt;

&lt;p&gt;If you plan to train custom models, initialize the training submodule and install its dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git submodule update &lt;span class="nt"&gt;--init&lt;/span&gt; tinker-atropos
uv pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"./tinker-atropos"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Initial Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Run the Setup Wizard
&lt;/h3&gt;

&lt;p&gt;For first-time setup, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The wizard helps you configure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LLM provider&lt;/li&gt;
&lt;li&gt;API keys&lt;/li&gt;
&lt;li&gt;Persistent memory&lt;/li&gt;
&lt;li&gt;Terminal backend&lt;/li&gt;
&lt;li&gt;Optional gateways such as Telegram, Discord, or Slack&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Manual Configuration
&lt;/h3&gt;

&lt;p&gt;Open the config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes config edit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or set values directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes config &lt;span class="nb"&gt;set &lt;/span&gt;model anthropic/claude-opus-4
hermes config &lt;span class="nb"&gt;set &lt;/span&gt;terminal.backend &lt;span class="nb"&gt;local
&lt;/span&gt;hermes config &lt;span class="nb"&gt;set &lt;/span&gt;OPENROUTER_API_KEY sk-or-...
hermes config &lt;span class="nb"&gt;set &lt;/span&gt;ANTHROPIC_API_KEY sk-ant-...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hermes stores API keys in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.hermes/.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not commit or share this file.&lt;/p&gt;




&lt;h3&gt;
  
  
  Configuration Directory
&lt;/h3&gt;

&lt;p&gt;Hermes stores local data under &lt;code&gt;~/.hermes/&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.hermes/
├── config.yaml      # Main configuration
├── .env             # API keys
├── memory/          # Persistent memory storage
├── skills/          # Installed skills
└── plugins/         # Custom plugins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Verify Your Setup
&lt;/h3&gt;

&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Config validity&lt;/li&gt;
&lt;li&gt;API key connectivity&lt;/li&gt;
&lt;li&gt;Memory status&lt;/li&gt;
&lt;li&gt;Gateway status&lt;/li&gt;
&lt;li&gt;Terminal backend connection&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Choose an LLM Provider
&lt;/h2&gt;

&lt;p&gt;Hermes can work with multiple model providers. Pick the provider based on cost, privacy, context length, and coding quality requirements.&lt;/p&gt;




&lt;h3&gt;
  
  
  OpenRouter
&lt;/h3&gt;

&lt;p&gt;OpenRouter is a good default because one API key gives access to many models.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes config &lt;span class="nb"&gt;set &lt;/span&gt;model openrouter
hermes config &lt;span class="nb"&gt;set &lt;/span&gt;OPENROUTER_API_KEY sk-or-...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example model choices:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Use case&lt;/th&gt;
&lt;th&gt;Relative cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;anthropic/claude-opus-4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Complex coding and reasoning&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;anthropic/claude-sonnet-4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Balanced development work&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;openai/gpt-4o&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;General-purpose tasks&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;google/gemini-pro-1.5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Long-context workflows&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;meta/llama-3-70b&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open-source, fast tasks&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  Anthropic Direct
&lt;/h3&gt;

&lt;p&gt;Use Anthropic directly if you want direct access to Claude models.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes config &lt;span class="nb"&gt;set &lt;/span&gt;model anthropic
hermes config &lt;span class="nb"&gt;set &lt;/span&gt;ANTHROPIC_API_KEY sk-ant-...
hermes config &lt;span class="nb"&gt;set &lt;/span&gt;model.default claude-opus-4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  OpenAI Direct
&lt;/h3&gt;

&lt;p&gt;Use OpenAI directly for GPT-4o or o1 workflows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes config &lt;span class="nb"&gt;set &lt;/span&gt;model openai
hermes config &lt;span class="nb"&gt;set &lt;/span&gt;OPENAI_API_KEY sk-...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Local Models with Ollama
&lt;/h3&gt;

&lt;p&gt;Use Ollama if you want local, private, offline-capable inference.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes config &lt;span class="nb"&gt;set &lt;/span&gt;model ollama
hermes config &lt;span class="nb"&gt;set &lt;/span&gt;model.default qwen2.5-coder:32b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install Ollama first from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://ollama.ai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Example Model Config
&lt;/h3&gt;

&lt;p&gt;Smart routing with fallbacks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;openrouter&lt;/span&gt;
  &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;anthropic/claude-opus-4&lt;/span&gt;
  &lt;span class="na"&gt;fallback&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;anthropic/claude-haiku-4-5&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;openai/gpt-4o-mini&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Budget controls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;budget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;daily_limit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5.00&lt;/span&gt;
    &lt;span class="na"&gt;monthly_limit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100.00&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Basic CLI Usage
&lt;/h2&gt;

&lt;p&gt;Start Hermes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then chat naturally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Help me write a Python function to parse JSON safely.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Useful Slash Commands
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; /help       # Show commands
&amp;gt; /skills     # Browse skills
&amp;gt; /memory     # View memory status
&amp;gt; /config     # View or edit config
&amp;gt; /clear      # Clear current conversation
&amp;gt; /history    # View past conversations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Work with Files
&lt;/h3&gt;

&lt;p&gt;Ask Hermes to inspect a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Look at ./src/main.py and explain the database connection flow.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ask it to edit a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; In main.py, change the database port from 5432 to 5433.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Create utils.py with helper functions for date formatting.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Run Terminal Commands
&lt;/h3&gt;

&lt;p&gt;You can ask Hermes to run commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Run: npm install &amp;amp;&amp;amp; npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hermes asks for confirmation before executing commands.&lt;/p&gt;




&lt;h3&gt;
  
  
  Use a Persistent Shell
&lt;/h3&gt;

&lt;p&gt;Hermes keeps shell state across commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; cd /my/project &amp;amp;&amp;amp; source venv/bin/activate
&amp;gt; python src/main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The virtual environment remains active for later commands in the same shell session.&lt;/p&gt;




&lt;h3&gt;
  
  
  Run Multi-Step Development Tasks
&lt;/h3&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Add user authentication to my Flask app:
&amp;gt; 1. Create database models
&amp;gt; 2. Add login and logout endpoints
&amp;gt; 3. Generate JWT tokens
&amp;gt; 4. Write tests for the auth flow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hermes can break the task into steps and ask for confirmation as it works.&lt;/p&gt;




&lt;h2&gt;
  
  
  Messaging Gateways
&lt;/h2&gt;

&lt;p&gt;Hermes can run as a bot in messaging platforms so you can use it from your phone or team chat.&lt;/p&gt;




&lt;h3&gt;
  
  
  Telegram Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open Telegram and search for &lt;code&gt;@BotFather&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Send &lt;code&gt;/newbot&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Follow the prompts&lt;/li&gt;
&lt;li&gt;Copy the bot token&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Configure Hermes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes config &lt;span class="nb"&gt;set &lt;/span&gt;TELEGRAM_BOT_TOKEN 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the gateway:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes gateway setup telegram
hermes gateway start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open your bot in Telegram, send &lt;code&gt;/start&lt;/code&gt;, and chat.&lt;/p&gt;




&lt;h3&gt;
  
  
  Discord Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;code&gt;https://discord.com/developers/applications&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a new application&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;Bot&lt;/strong&gt; section&lt;/li&gt;
&lt;li&gt;Create a bot and copy the token&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;OAuth2 → URL Generator&lt;/strong&gt; to invite the bot to your server&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Configure Hermes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes config &lt;span class="nb"&gt;set &lt;/span&gt;DISCORD_BOT_TOKEN MTIzNDU2...
hermes gateway setup discord
hermes gateway start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use it by mentioning the bot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Hermes help me write a function that validates email addresses
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use it in DMs.&lt;/p&gt;




&lt;h3&gt;
  
  
  Slack Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;code&gt;https://api.slack.com/apps&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a new app from scratch&lt;/li&gt;
&lt;li&gt;Add bot permissions&lt;/li&gt;
&lt;li&gt;Install the app to your workspace&lt;/li&gt;
&lt;li&gt;Copy the bot token&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Configure Hermes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes config &lt;span class="nb"&gt;set &lt;/span&gt;SLACK_BOT_TOKEN xoxb-...
hermes gateway setup slack
hermes gateway start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Run All Gateways
&lt;/h3&gt;

&lt;p&gt;To start every configured gateway:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes gateway start &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hermes syncs conversation state across platforms.&lt;/p&gt;




&lt;h2&gt;
  
  
  IDE Integration
&lt;/h2&gt;

&lt;p&gt;Hermes integrates with editors through the Agent Communication Protocol.&lt;/p&gt;




&lt;h3&gt;
  
  
  VS Code
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open Extensions with &lt;code&gt;Ctrl+Shift+X&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;Agent Communication Protocol&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install the extension&lt;/li&gt;
&lt;li&gt;Start the Hermes ACP server:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes acp start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open the ACP sidebar, select Hermes, and chat from the editor.&lt;/p&gt;




&lt;h3&gt;
  
  
  JetBrains IDEs
&lt;/h3&gt;

&lt;p&gt;For IntelliJ, PyCharm, and other JetBrains IDEs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;Settings → Plugins&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;ACP&lt;/code&gt; or &lt;code&gt;Agent Communication Protocol&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install the plugin&lt;/li&gt;
&lt;li&gt;Restart the IDE&lt;/li&gt;
&lt;li&gt;Start Hermes:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes acp start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then configure Hermes under:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Settings → Tools → AI Agents
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Zed
&lt;/h3&gt;

&lt;p&gt;Configure Zed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"agent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"acp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"endpoint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hermes"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start Hermes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes acp start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Memory and Learning
&lt;/h2&gt;

&lt;p&gt;Hermes uses memory to make future sessions more useful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Memory Types
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Episodic memory&lt;/td&gt;
&lt;td&gt;Stores conversations and sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Semantic memory&lt;/td&gt;
&lt;td&gt;Builds knowledge about projects, preferences, and patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Procedural memory&lt;/td&gt;
&lt;td&gt;Stores reusable skills and workflows&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Search memory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; /memory search "database migration"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List project memory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; /memory projects
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List skills:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; /skills list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Search Past Sessions
&lt;/h3&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; /memory search "How did we handle JWT expiration last week?"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hermes searches prior context and summarizes relevant results.&lt;/p&gt;




&lt;h3&gt;
  
  
  Memory Nudges
&lt;/h3&gt;

&lt;p&gt;Hermes can surface related context while you work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Hermes]: I noticed you're working on the auth system. Last Tuesday you
mentioned a problem with JWT expiration. Want to revisit that?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Context Compression
&lt;/h3&gt;

&lt;p&gt;Hermes automatically compresses context to avoid hitting model limits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gateway compression at 85% context usage&lt;/li&gt;
&lt;li&gt;Agent-level compression at 50%, configurable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This helps keep long conversations usable without manual pruning.&lt;/p&gt;




&lt;h3&gt;
  
  
  Backup and Restore Memory
&lt;/h3&gt;

&lt;p&gt;Export memory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes memory &lt;span class="nb"&gt;export&lt;/span&gt; ~/backup/hermes-memory.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Import memory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes memory import ~/backup/hermes-memory.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Skills and Plugins
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Skills
&lt;/h3&gt;

&lt;p&gt;Skills are reusable workflows Hermes can execute.&lt;/p&gt;

&lt;p&gt;Built-in examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;code_review&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;debug_session&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;api_tester&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git_workflow&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;documentation&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;List skills:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; /skills list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install a skill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; /skills install code_review
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run a skill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; /skills run code_review ./src/auth.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Create a Custom Skill
&lt;/h3&gt;

&lt;p&gt;Create a file under &lt;code&gt;~/.hermes/skills/&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ~/.hermes/skills/my_skill.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hermes.skills&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Skill&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyCustomSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Skill&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my_custom_skill&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Does something useful&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Your skill logic here
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Skill executed successfully&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Plugins
&lt;/h3&gt;

&lt;p&gt;Plugins extend Hermes with custom tools, slash commands, and lifecycle hooks.&lt;/p&gt;

&lt;p&gt;Example custom tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ~/.hermes/plugins/my_tool.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hermes.tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Tool&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyCustomTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my_tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A custom tool for specific tasks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Tool logic here
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plugin types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt;: new capabilities the agent can use&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commands&lt;/strong&gt;: new slash commands&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hooks&lt;/strong&gt;: before/after turn handlers&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Advanced Workflows
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cron Scheduling
&lt;/h3&gt;

&lt;p&gt;Ask Hermes to create a scheduled task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Set up a daily digest of my GitHub notifications at 9am.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or configure a task manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Daily&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;digest"&lt;/span&gt;
    &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;9&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/skills&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;github_digest"&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anthropic/claude-haiku-4-5"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Subagent Delegation
&lt;/h3&gt;

&lt;p&gt;Hermes can spawn subagents for parallel work.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Review all PRs in my repo and summarize the changes.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hermes can delegate work to multiple subagents and synthesize the results.&lt;/p&gt;




&lt;h3&gt;
  
  
  Voice Mode
&lt;/h3&gt;

&lt;p&gt;Start CLI voice mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes &lt;span class="nt"&gt;--voice&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Messaging platforms can also support voice-note workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send a voice message&lt;/li&gt;
&lt;li&gt;Hermes transcribes it&lt;/li&gt;
&lt;li&gt;Hermes responds in the chat&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Discord voice channels, Hermes can join and handle real-time voice interaction.&lt;/p&gt;




&lt;h3&gt;
  
  
  Browser Control
&lt;/h3&gt;

&lt;p&gt;Hermes can integrate with Browser Use CLI 2.0 for web automation.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Go to github.com and find the top 5 trending Python repos.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Connect to a live Chrome instance with CDP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes browser connect &lt;span class="nt"&gt;--cdp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  MCP Integration
&lt;/h3&gt;

&lt;p&gt;Hermes supports Model Context Protocol servers.&lt;/p&gt;

&lt;p&gt;Example config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;mcp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;servers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;filesystem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;npx"&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-y"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@modelcontextprotocol/server-filesystem"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;~/projects"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;git&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;npx"&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-y"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@modelcontextprotocol/server-git"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Worktree Mode
&lt;/h3&gt;

&lt;p&gt;Run Hermes in an isolated Git worktree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes &lt;span class="nt"&gt;-w&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lets multiple agents work on the same repo concurrently without conflicting changes.&lt;/p&gt;




&lt;h3&gt;
  
  
  Run Other Agents Inside Hermes
&lt;/h3&gt;

&lt;p&gt;You can ask Hermes to call another specialized agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; Use claude-code to review this pull request.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful when a subagent is better suited for a specific task.&lt;/p&gt;




&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;h3&gt;
  
  
  API Key Not Found
&lt;/h3&gt;

&lt;p&gt;Check whether the key is set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes config get OPENROUTER_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set it again if needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes config &lt;span class="nb"&gt;set &lt;/span&gt;OPENROUTER_API_KEY sk-or-...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Model Not Available
&lt;/h3&gt;

&lt;p&gt;List available models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes models list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change the model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes config &lt;span class="nb"&gt;set &lt;/span&gt;model anthropic/claude-opus-4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Gateway Failed to Start
&lt;/h3&gt;

&lt;p&gt;Check status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes gateway status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes gateway stop
hermes gateway start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Memory Corruption Detected
&lt;/h3&gt;

&lt;p&gt;Back up memory first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes memory &lt;span class="nb"&gt;export&lt;/span&gt; ~/backup/memory-backup.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reset memory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes memory reset
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Re-import if needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes memory import ~/backup/memory-backup.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Get Help
&lt;/h3&gt;

&lt;p&gt;Inside Hermes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; /help
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;View logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes logs &lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;--follow&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run diagnostics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How much does Hermes cost?
&lt;/h3&gt;

&lt;p&gt;Hermes itself is free. You pay for LLM usage.&lt;/p&gt;

&lt;p&gt;Typical monthly ranges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Light use: &lt;code&gt;$5–15&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Moderate development use: &lt;code&gt;$20–50&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Heavy automation: &lt;code&gt;$50–200&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Local models through Ollama can avoid API usage costs but require suitable hardware.&lt;/p&gt;




&lt;h3&gt;
  
  
  Can Hermes run 24/7?
&lt;/h3&gt;

&lt;p&gt;Yes. For example, on a VPS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash

hermes service &lt;span class="nb"&gt;install
&lt;/span&gt;hermes service start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Is Hermes suitable for enterprise use?
&lt;/h3&gt;

&lt;p&gt;Hermes includes features relevant to enterprise deployments, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-user gateway mode with session isolation&lt;/li&gt;
&lt;li&gt;PII redaction&lt;/li&gt;
&lt;li&gt;Supply chain security hardening&lt;/li&gt;
&lt;li&gt;Self-hosted deployment&lt;/li&gt;
&lt;li&gt;Audit logging&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  How do I migrate from OpenClaw?
&lt;/h3&gt;

&lt;p&gt;Preview the migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes claw migrate &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes claw migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Can I use Hermes without internet?
&lt;/h3&gt;

&lt;p&gt;Yes, with local models.&lt;/p&gt;

&lt;p&gt;Install Ollama:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://ollama.ai/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pull a model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama pull qwen2.5-coder:32b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure Hermes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes config &lt;span class="nb"&gt;set &lt;/span&gt;model ollama
hermes config &lt;span class="nb"&gt;set &lt;/span&gt;model.default qwen2.5-coder:32b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Hermes vs. ChatGPT
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Hermes&lt;/th&gt;
&lt;th&gt;ChatGPT&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Memory&lt;/td&gt;
&lt;td&gt;Persistent and searchable&lt;/td&gt;
&lt;td&gt;Session-only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;Self-hosted, can run 24/7&lt;/td&gt;
&lt;td&gt;Cloud-only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model choice&lt;/td&gt;
&lt;td&gt;200+ models&lt;/td&gt;
&lt;td&gt;GPT models&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extensibility&lt;/td&gt;
&lt;td&gt;Plugins and skills&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost model&lt;/td&gt;
&lt;td&gt;Pay for usage&lt;/td&gt;
&lt;td&gt;Subscription&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Privacy&lt;/td&gt;
&lt;td&gt;You control deployment and data&lt;/td&gt;
&lt;td&gt;OpenAI stores data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  How do I back up all Hermes data?
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;hermes &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; ~/backup/hermes-full-backup.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Can Hermes access my local files?
&lt;/h3&gt;

&lt;p&gt;Hermes can access files you explicitly reference or directories you grant permission to. By default, it does not have unrestricted filesystem access.&lt;/p&gt;




&lt;p&gt;Want to include API testing in your AI-assisted development workflow? Use Apidog to design, test, and document APIs alongside your agent-based coding process.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Qwen 3.6 Available on OpenRouter: How to Use It Right Now</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Thu, 25 Jun 2026 01:03:12 +0000</pubDate>
      <link>https://dev.to/preecha/qwen-36-available-on-openrouter-how-to-use-it-right-now-1fk2</link>
      <guid>https://dev.to/preecha/qwen-36-available-on-openrouter-how-to-use-it-right-now-1fk2</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Qwen 3.6 Plus Preview launched on March 30, 2026, with a 1-million-token context window, mandatory chain-of-thought reasoning, and tool use support. It is currently free on OpenRouter. Use the model ID &lt;code&gt;qwen/qwen3.6-plus-preview:free&lt;/code&gt; with any OpenAI-compatible client to start sending requests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  The model that showed up quietly
&lt;/h2&gt;

&lt;p&gt;Alibaba Cloud released Qwen 3.6 Plus Preview on March 30, 2026. There was no waitlist or major launch campaign. The model appeared on OpenRouter at &lt;code&gt;$0&lt;/code&gt; per million tokens.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1sovt2j08pac59126ya.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1sovt2j08pac59126ya.png" alt="Image" width="800" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In its first two days, it processed more than 400 million completion tokens across roughly 400,000 requests. Developers also reported fast responses.&lt;/p&gt;

&lt;p&gt;This guide shows how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an OpenRouter account&lt;/li&gt;
&lt;li&gt;Generate an API key&lt;/li&gt;
&lt;li&gt;Call Qwen 3.6 with cURL, Python, Node.js, and the OpenAI SDK&lt;/li&gt;
&lt;li&gt;Use tool calling for agentic workflows&lt;/li&gt;
&lt;li&gt;Work with the 1M-token context window&lt;/li&gt;
&lt;li&gt;Test OpenRouter requests with Apidog&lt;/li&gt;
&lt;li&gt;Plan around free-tier limitations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you build on top of AI APIs, you also need a reliable way to test and debug HTTP requests. Apidog can help with request building, response inspection, and API test automation for REST APIs including OpenRouter.&lt;/p&gt;

&lt;p&gt;By the end, you should be able to call Qwen 3.6 for free, understand where it works well, and know what constraints to account for before using it in an app.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Qwen 3.6 adds over the 3.5 series
&lt;/h2&gt;

&lt;p&gt;The jump from Qwen 3.5 to Qwen 3.6 is meaningful in three areas.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The context window grew to 1 million tokens
&lt;/h3&gt;

&lt;p&gt;Qwen 3.5 supported a 32K to 128K context window depending on the variant. Qwen 3.6 supports up to 1 million input tokens.&lt;/p&gt;

&lt;p&gt;In practical terms, 1 million tokens is roughly 750,000 words. That is enough to pass in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A large codebase&lt;/li&gt;
&lt;li&gt;Long Slack or support logs&lt;/li&gt;
&lt;li&gt;A full legal document set&lt;/li&gt;
&lt;li&gt;A research corpus&lt;/li&gt;
&lt;li&gt;Large API documentation sets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most free models top out around 8K to 32K tokens, so 1M tokens at the free tier is unusual.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Reasoning is built in
&lt;/h3&gt;

&lt;p&gt;Qwen 3.6 uses mandatory reasoning tokens. Before returning the final answer, the model performs internal chain-of-thought reasoning.&lt;/p&gt;

&lt;p&gt;You do not need to add prompts like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Think step by step.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is similar to the pattern popularized by DeepSeek R1. Qwen 3.6 applies it across coding, front-end development, and general problem-solving tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Tool use is more reliable
&lt;/h3&gt;

&lt;p&gt;Tool calling in the Qwen 3.5 series could be inconsistent. Common issues included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Incorrect function argument types&lt;/li&gt;
&lt;li&gt;Hallucinated tool names&lt;/li&gt;
&lt;li&gt;Invalid JSON arguments&lt;/li&gt;
&lt;li&gt;Missed tool calls in multi-step workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alibaba Cloud describes Qwen 3.6 as delivering “stronger reasoning and more reliable agentic behavior compared to the 3.5 series.”&lt;/p&gt;

&lt;p&gt;For developers, that mainly means fewer broken tool calls when building agents.&lt;/p&gt;

&lt;p&gt;Qwen 3.6 is tuned for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agentic coding: multi-step code generation with tool use&lt;/li&gt;
&lt;li&gt;Front-end development: HTML, CSS, JavaScript, and component generation&lt;/li&gt;
&lt;li&gt;Complex problem-solving: research, analysis, and long-context summarization&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to access Qwen 3.6 for free
&lt;/h2&gt;

&lt;p&gt;You need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An OpenRouter account&lt;/li&gt;
&lt;li&gt;An OpenRouter API key&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No credit card is required for free models.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Create an OpenRouter account
&lt;/h3&gt;

&lt;p&gt;Go to &lt;code&gt;openrouter.ai&lt;/code&gt; and sign up with email or Google.&lt;/p&gt;

&lt;p&gt;After email verification, you can use free models without adding a payment method.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Generate an API key
&lt;/h3&gt;

&lt;p&gt;In OpenRouter:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click your profile avatar in the top-right corner&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;API Keys&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create Key&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Give the key a name, for example &lt;code&gt;qwen-test&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Copy the key&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key starts with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sk-or-v1-...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpm80wt8cpulj2nl1hj49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpm80wt8cpulj2nl1hj49.png" alt="Image" width="799" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Store it securely. OpenRouter will not show it again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Send your first request
&lt;/h3&gt;

&lt;p&gt;Use this model ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qwen/qwen3.6-plus-preview:free
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OpenRouter uses an OpenAI-compatible API format, so most OpenAI SDKs and clients work with only a base URL change.&lt;/p&gt;

&lt;h3&gt;
  
  
  cURL
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://openrouter.ai/api/v1/chat/completions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer sk-or-v1-YOUR_KEY_HERE"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "model": "qwen/qwen3.6-plus-preview:free",
    "messages": [
      {
        "role": "user",
        "content": "Write a Python function that parses a JWT token and returns the payload as a dictionary."
      }
    ]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python with &lt;code&gt;requests&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call_qwen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://openrouter.ai/api/v1/chat/completions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen/qwen3.6-plus-preview:free&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;choices&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;call_qwen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Write a Python function that parses a JWT token and returns the payload.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-or-v1-YOUR_KEY_HERE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Node.js with &lt;code&gt;fetch&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;callQwen&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="nx"&gt;apiKey&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;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://openrouter.ai/api/v1/chat/completions&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="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&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="na"&gt;body&lt;/span&gt;&lt;span class="p"&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;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;qwen/qwen3.6-plus-preview:free&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&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="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`OpenRouter error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&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;data&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;callQwen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Write a JavaScript function that validates an email address.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sk-or-v1-YOUR_KEY_HERE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python with the OpenAI SDK
&lt;/h3&gt;

&lt;p&gt;If you already use the OpenAI Python SDK, point it at OpenRouter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://openrouter.ai/api/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-or-v1-YOUR_KEY_HERE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen/qwen3.6-plus-preview:free&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;system&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are a senior backend engineer. Write clean, production-ready code.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Write a Python function that retries a failed HTTP request up to 3 times with exponential backoff.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tool use and agentic workflows
&lt;/h2&gt;

&lt;p&gt;Tool use is where Qwen 3.6 is especially useful at the free tier.&lt;/p&gt;

&lt;p&gt;The pattern is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Define tools as JSON schemas&lt;/li&gt;
&lt;li&gt;Send the user request plus tool definitions&lt;/li&gt;
&lt;li&gt;Let the model choose a tool&lt;/li&gt;
&lt;li&gt;Execute the tool in your code&lt;/li&gt;
&lt;li&gt;Send the tool result back to the model&lt;/li&gt;
&lt;li&gt;Repeat until the task is complete&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is a minimal tool-calling example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://openrouter.ai/api/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-or-v1-YOUR_KEY_HERE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search_api_docs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Search the API documentation for a specific endpoint or parameter&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parameters&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The search query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;enum&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;v2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;v3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API version to search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;run_api_test&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Execute a test request against an API endpoint&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parameters&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;endpoint&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;method&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;enum&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PUT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DELETE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;endpoint&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;method&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Find documentation for the /users endpoint and run a test GET request against it.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen/qwen3.6-plus-preview:free&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tool_choice&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auto&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tool_calls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tool_call&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tool_calls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tool: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Arguments: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model should return a structured function call instead of a free-form answer. Your app is still responsible for executing the function and returning the result in the next turn.&lt;/p&gt;

&lt;p&gt;That loop is the core of most agentic workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the 1 million token context window
&lt;/h2&gt;

&lt;p&gt;A 1M-token context window is not useful for simple prompts. It is useful when the model needs a large amount of context in a single request.&lt;/p&gt;

&lt;p&gt;Good use cases include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full codebase review&lt;/li&gt;
&lt;li&gt;Large document analysis&lt;/li&gt;
&lt;li&gt;Long technical debugging sessions&lt;/li&gt;
&lt;li&gt;API documentation comparison&lt;/li&gt;
&lt;li&gt;Research corpus summarization&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Full codebase review
&lt;/h3&gt;

&lt;p&gt;You can load source files into one prompt and ask the model to inspect them for specific issues.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://openrouter.ai/api/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-or-v1-YOUR_KEY_HERE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_codebase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Load all source files from a directory into a single string.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;content_parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;rglob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;suffix&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;extensions&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_file&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ignore&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;content_parts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--- FILE: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ---&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;continue&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content_parts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;codebase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_codebase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./src&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.js&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.ts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen/qwen3.6-plus-preview:free&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Review this codebase and identify:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1. Security vulnerabilities&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2. Functions with no error handling&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3. Inconsistent naming conventions&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Codebase:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;codebase&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When using this pattern, filter out files that add noise:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;node_modules&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Build artifacts&lt;/li&gt;
&lt;li&gt;Lock files&lt;/li&gt;
&lt;li&gt;Generated files&lt;/li&gt;
&lt;li&gt;Binary files&lt;/li&gt;
&lt;li&gt;Test snapshots&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Large document analysis
&lt;/h3&gt;

&lt;p&gt;For long reports, legal documents, or API docs, pass the full document and ask for specific extraction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://openrouter.ai/api/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-or-v1-YOUR_KEY_HERE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;annual_report_2025.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen/qwen3.6-plus-preview:free&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Extract all mentions of API rate limits and pricing changes &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;from this document:&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Multi-turn conversation with full history
&lt;/h3&gt;

&lt;p&gt;For long debugging sessions, keep the entire conversation in memory and send it with each request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://openrouter.ai/api/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-or-v1-YOUR_KEY_HERE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;conversation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user_message&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen/qwen3.6-plus-preview:free&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;assistant_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
    &lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;assistant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;assistant_message&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;assistant_message&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;m getting a 401 error from the GitHub API. Here&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s my code...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I added the token but now I get a 403. The token has repo scope.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The repo is private. What scopes do I actually need?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing OpenRouter API requests with Apidog
&lt;/h2&gt;

&lt;p&gt;When you build against the OpenRouter API, you need to debug HTTP requests, inspect JSON responses, and iterate on prompts. Doing that only from the command line can get slow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpm80wt8cpulj2nl1hj49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpm80wt8cpulj2nl1hj49.png" alt="Image" width="799" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Apidog is a free API client for request building, response inspection, and test automation.&lt;/p&gt;

&lt;p&gt;To test Qwen 3.6 in Apidog:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new &lt;code&gt;POST&lt;/code&gt; request&lt;/li&gt;
&lt;li&gt;Set the URL:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://openrouter.ai/api/v1/chat/completions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Add the authorization header:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authorization: Bearer sk-or-v1-YOUR_KEY_HERE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Add the content type header:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Content-Type: application/json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Set the request body:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"qwen/qwen3.6-plus-preview:free"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"messages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Write a TypeScript function that validates an email address."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Send the request and inspect the response.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can also save the request in a collection and create tests such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;choices&lt;/code&gt; exists&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;choices[0].message.content&lt;/code&gt; is not empty&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;choices[0].message.tool_calls&lt;/code&gt; contains the expected function name&lt;/li&gt;
&lt;li&gt;The response status is &lt;code&gt;200&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The model returns valid JSON when your prompt requires JSON&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a basic response-shape test could assert that the assistant message exists before your app depends on it.&lt;/p&gt;

&lt;p&gt;If your app calls OpenRouter in production, adding these tests early makes it easier to catch model, schema, or integration regressions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Free tier limits to know before you build
&lt;/h2&gt;

&lt;p&gt;Qwen 3.6 is free now, but you should still design around free-tier constraints.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rate limits are shared
&lt;/h3&gt;

&lt;p&gt;Free models on OpenRouter share capacity across users. During peak hours, such as US evenings, you may see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Higher latency&lt;/li&gt;
&lt;li&gt;Occasional rate limit errors&lt;/li&gt;
&lt;li&gt;Temporary failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add retry logic before using the endpoint in any production workflow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;requests.adapters&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HTTPAdapter&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib3.util.retry&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Retry&lt;/span&gt;

&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;retry_strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;backoff_factor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;status_forcelist&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;502&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;504&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HTTPAdapter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_retries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;retry_strategy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://openrouter.ai/api/v1/chat/completions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer sk-or-v1-YOUR_KEY_HERE&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen/qwen3.6-plus-preview:free&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Data is logged
&lt;/h3&gt;

&lt;p&gt;OpenRouter’s model page states that “the model collects prompt and completion data that can be used to improve the model.”&lt;/p&gt;

&lt;p&gt;Do not send:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API keys&lt;/li&gt;
&lt;li&gt;Passwords&lt;/li&gt;
&lt;li&gt;Private tokens&lt;/li&gt;
&lt;li&gt;Personally identifiable information&lt;/li&gt;
&lt;li&gt;Confidential customer data&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Preview behavior can change
&lt;/h3&gt;

&lt;p&gt;Qwen 3.6 Plus Preview is a preview release. Model behavior may change.&lt;/p&gt;

&lt;p&gt;If you use it for production inference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pin your integration to the current model ID&lt;/li&gt;
&lt;li&gt;Add regression tests for important prompts&lt;/li&gt;
&lt;li&gt;Monitor response format changes&lt;/li&gt;
&lt;li&gt;Keep fallback model options ready&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Text only
&lt;/h3&gt;

&lt;p&gt;Qwen 3.6 accepts text input and produces text output.&lt;/p&gt;

&lt;p&gt;It does not support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Images&lt;/li&gt;
&lt;li&gt;Audio&lt;/li&gt;
&lt;li&gt;File uploads&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-world use cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Code review agent
&lt;/h3&gt;

&lt;p&gt;A team building an internal PR review tool can pass full pull request diffs into Qwen 3.6 and ask for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logic errors&lt;/li&gt;
&lt;li&gt;Missing tests&lt;/li&gt;
&lt;li&gt;Security issues&lt;/li&gt;
&lt;li&gt;Risky dependency changes&lt;/li&gt;
&lt;li&gt;Inconsistent patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 1M-token context window makes this possible without splitting many large diffs into chunks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Front-end component generation
&lt;/h3&gt;

&lt;p&gt;For front-end work, you can give the model a design spec and ask for React, TypeScript, HTML, CSS, or JavaScript components.&lt;/p&gt;

&lt;p&gt;Example prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generate a responsive React TypeScript pricing table component.

Requirements:
- Three pricing tiers
- Monthly and yearly toggle
- Accessible buttons
- Mobile-first layout
- Tailwind CSS classes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Qwen 3.6 is tuned for front-end development tasks, so this is a strong fit.&lt;/p&gt;

&lt;h3&gt;
  
  
  API documentation summarization
&lt;/h3&gt;

&lt;p&gt;If you are comparing two third-party APIs, pass in the relevant docs and ask for a structured comparison.&lt;/p&gt;

&lt;p&gt;Useful comparison dimensions include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication methods&lt;/li&gt;
&lt;li&gt;Rate limits&lt;/li&gt;
&lt;li&gt;Webhook payloads&lt;/li&gt;
&lt;li&gt;Error response formats&lt;/li&gt;
&lt;li&gt;Pagination models&lt;/li&gt;
&lt;li&gt;Pricing-related API constraints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Compare these two payment API documentation sets.

Return a table with:
1. Authentication method
2. Webhook verification flow
3. Rate limit policy
4. Pagination style
5. Refund API behavior
6. Migration risks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is Qwen 3.6 actually free to use?
&lt;/h3&gt;

&lt;p&gt;Yes. As of March 2026, the model is listed at &lt;code&gt;$0&lt;/code&gt; per million input tokens and &lt;code&gt;$0&lt;/code&gt; per million output tokens on OpenRouter.&lt;/p&gt;

&lt;p&gt;That can change when the preview period ends, so check OpenRouter pricing before building anything that depends on the price staying at zero.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the rate limit for the free tier?
&lt;/h3&gt;

&lt;p&gt;OpenRouter does not publish exact rate limits for free-tier models.&lt;/p&gt;

&lt;p&gt;In practice, free models share capacity and can be throttled during high-traffic periods. Start with one request at a time, add retry logic, and increase concurrency gradually.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use Qwen 3.6 for commercial projects?
&lt;/h3&gt;

&lt;p&gt;Yes, OpenRouter allows commercial use.&lt;/p&gt;

&lt;p&gt;Also check Alibaba Cloud’s Qwen model license for restrictions on the underlying model, especially if you are distributing outputs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does Qwen 3.6 take longer to respond than other models?
&lt;/h3&gt;

&lt;p&gt;Mandatory reasoning tokens add latency. Before producing the final response, the model performs internal reasoning.&lt;/p&gt;

&lt;p&gt;For simple prompts, this can add a few seconds. For complex reasoning tasks, the tradeoff may be worth it.&lt;/p&gt;

&lt;p&gt;Use streaming if you want to show partial output while the response is generated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is there a way to disable reasoning tokens?
&lt;/h3&gt;

&lt;p&gt;As of the current preview, reasoning is mandatory and cannot be turned off.&lt;/p&gt;

&lt;p&gt;If you need lower latency without chain-of-thought reasoning, use a different model variant when available or a smaller free model for latency-sensitive tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does the 1M-token context window affect cost?
&lt;/h3&gt;

&lt;p&gt;On the free tier, it does not affect cost. You pay &lt;code&gt;$0&lt;/code&gt; regardless of the number of tokens sent.&lt;/p&gt;

&lt;p&gt;However, very large requests take longer and may time out. Start with a &lt;code&gt;30&lt;/code&gt; to &lt;code&gt;60&lt;/code&gt; second timeout and increase it for requests over 100K tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final setup checklist
&lt;/h2&gt;

&lt;p&gt;To start using Qwen 3.6:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an OpenRouter account&lt;/li&gt;
&lt;li&gt;Generate an API key&lt;/li&gt;
&lt;li&gt;Use this model ID:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qwen/qwen3.6-plus-preview:free
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Send requests to:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://openrouter.ai/api/v1/chat/completions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Add retry logic for &lt;code&gt;429&lt;/code&gt; and &lt;code&gt;5xx&lt;/code&gt; errors&lt;/li&gt;
&lt;li&gt;Avoid sending secrets or sensitive data&lt;/li&gt;
&lt;li&gt;Test your requests and response assumptions before shipping&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once your API key is ready, you can swap &lt;code&gt;qwen/qwen3.6-plus-preview:free&lt;/code&gt; into any OpenAI-compatible client and start testing.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Claude Code Can Now Control Your Mac. Here's How to Use It</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Wed, 24 Jun 2026 13:03:13 +0000</pubDate>
      <link>https://dev.to/preecha/claude-code-can-now-control-your-mac-heres-how-to-use-it-3am6</link>
      <guid>https://dev.to/preecha/claude-code-can-now-control-your-mac-heres-how-to-use-it-3am6</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Claude Code can now control your Mac from the same terminal session where it writes code. It can open apps, click through UIs, run tests, capture screenshots, and use the results to patch code. The feature is a research preview for Pro and Max plan subscribers on macOS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;To enable it, run &lt;code&gt;/mcp&lt;/code&gt; in Claude Code, enable the &lt;code&gt;computer-use&lt;/code&gt; MCP server, then grant macOS Accessibility and Screen Recording permissions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Claude can now use your computer
&lt;/h2&gt;

&lt;p&gt;Anthropic announced Claude Code computer use on March 23, 2026. The workflow is simple: Claude writes code, runs it, interacts with the UI, observes the result, and fixes issues without you leaving the terminal.&lt;/p&gt;

&lt;p&gt;Before computer use, Claude could generate a macOS menu bar app, but you still had to compile it, launch it, click through the UI, and report back what failed.&lt;/p&gt;

&lt;p&gt;Now you can ask for the whole loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build this app and make sure it works.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude can compile the project, launch the binary, interact with controls, screenshot failures, inspect the relevant source, patch the issue, and re-run the flow.&lt;/p&gt;

&lt;p&gt;That changes the unit of work from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write this feature.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build this feature, run it, and verify the UI behavior.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’re building on APIs, this is useful for GUI-driven flows that do not expose a CLI or API. Claude can verify the app behavior visually, and you can then build automated API test suites in Apidog to validate the same flows programmatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can do with it
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Build and validate native apps end-to-end
&lt;/h3&gt;

&lt;p&gt;Use computer use when you want Claude to verify the result in the actual app, not just generate code.&lt;/p&gt;

&lt;p&gt;Example prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build the MenuBarStats target, launch it, open the preferences window,
and verify the interval slider updates the label. Screenshot the
preferences window when done.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;xcodebuild&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Launch the compiled app&lt;/li&gt;
&lt;li&gt;Open the preferences window&lt;/li&gt;
&lt;li&gt;Move the slider&lt;/li&gt;
&lt;li&gt;Check whether the label updates&lt;/li&gt;
&lt;li&gt;Screenshot the final state&lt;/li&gt;
&lt;li&gt;Patch and re-test if something fails&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You get a verified build instead of a code-only draft.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run UI checks without setting up a test framework
&lt;/h3&gt;

&lt;p&gt;For early-stage projects, you may not want to configure Playwright, Selenium, or XCTest yet.&lt;/p&gt;

&lt;p&gt;Prompt Claude with the flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Open the app, click through the onboarding screens, and tell me if any
screen takes more than a second to load.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude can open the app, click through the UI, screenshot each step, and flag slow or broken transitions.&lt;/p&gt;

&lt;p&gt;This is useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Electron apps&lt;/li&gt;
&lt;li&gt;Native macOS apps&lt;/li&gt;
&lt;li&gt;iOS Simulator flows&lt;/li&gt;
&lt;li&gt;GUI-only tools&lt;/li&gt;
&lt;li&gt;Prototypes without formal test coverage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is not a replacement for deterministic production test suites, but it is fast for exploratory validation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Debug visual and layout bugs
&lt;/h3&gt;

&lt;p&gt;Visual bugs are often hard to describe precisely. With computer use, Claude can reproduce the UI state directly.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The settings modal clips its footer on narrow windows. Resize the app
window until you can reproduce it, screenshot the clipped state, then
check the CSS for the modal container.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resize the app window&lt;/li&gt;
&lt;li&gt;Capture the broken layout&lt;/li&gt;
&lt;li&gt;Inspect the relevant CSS&lt;/li&gt;
&lt;li&gt;Apply a fix&lt;/li&gt;
&lt;li&gt;Re-test the same window size&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This works well for issues such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Overflow bugs&lt;/li&gt;
&lt;li&gt;Clipped footers&lt;/li&gt;
&lt;li&gt;Broken responsive layouts&lt;/li&gt;
&lt;li&gt;Misaligned controls&lt;/li&gt;
&lt;li&gt;Modals that fail at narrow widths&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drive GUI-only tools
&lt;/h3&gt;

&lt;p&gt;Some tools do not expose useful automation APIs. Examples include design tools, hardware control panels, proprietary enterprise apps, and simulators.&lt;/p&gt;

&lt;p&gt;With computer use, you can describe the interaction in natural language and let Claude operate the UI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Open the simulator, launch the app, tap through onboarding, and screenshot
each screen where the UI changes.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpwchcytg3lqx28mu6us0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpwchcytg3lqx28mu6us0.gif" alt="Image" width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to enable computer use
&lt;/h2&gt;

&lt;p&gt;Computer use is disabled by default. It ships as a built-in MCP server named &lt;code&gt;computer-use&lt;/code&gt;, and you enable it per project.&lt;/p&gt;

&lt;p&gt;Before you start, confirm these requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;macOS only&lt;/li&gt;
&lt;li&gt;Claude Code &lt;code&gt;v2.1.85&lt;/code&gt; or later&lt;/li&gt;
&lt;li&gt;Pro or Max plan&lt;/li&gt;
&lt;li&gt;Authentication through &lt;code&gt;claude.ai&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Interactive Claude Code session&lt;/li&gt;
&lt;li&gt;Not using the &lt;code&gt;-p&lt;/code&gt; non-interactive flag&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check your Claude Code version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update if needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @anthropic-ai/claude-code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 1: Open the MCP menu
&lt;/h3&gt;

&lt;p&gt;In an active Claude Code session, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This opens the server list.&lt;/p&gt;

&lt;p&gt;Find:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;computer-use
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should appear as disabled.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Enable the server
&lt;/h3&gt;

&lt;p&gt;Select &lt;code&gt;computer-use&lt;/code&gt;, then choose &lt;strong&gt;Enable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This setting persists per project. You only need to enable it once for each project where you want Claude to control the GUI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Grant macOS permissions
&lt;/h3&gt;

&lt;p&gt;The first time Claude tries to control your screen, macOS prompts for two permissions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: allows Claude to click, type, and scroll&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Screen Recording&lt;/strong&gt;: allows Claude to see what is on screen&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The prompts include links to the relevant System Settings panes.&lt;/p&gt;

&lt;p&gt;After granting Screen Recording, restart Claude Code if the permission does not take effect immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Run a GUI verification prompt
&lt;/h3&gt;

&lt;p&gt;Try a small, low-risk workflow first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build the app target, launch it, and click through each tab to confirm
nothing crashes. Screenshot any error states you find.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start with test apps or isolated development environments before using computer use on workflows that contain sensitive data.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Claude works on your screen
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Only one session can control your Mac
&lt;/h3&gt;

&lt;p&gt;Computer use uses a machine-wide lock.&lt;/p&gt;

&lt;p&gt;If another Claude Code session is already using computer use, new requests fail with a message showing which session holds the lock.&lt;/p&gt;

&lt;p&gt;To continue:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Finish the active computer use task.&lt;/li&gt;
&lt;li&gt;Exit the other Claude Code session.&lt;/li&gt;
&lt;li&gt;Retry the request.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Other apps hide while Claude works
&lt;/h3&gt;

&lt;p&gt;When Claude takes control, visible apps hide so Claude interacts only with approved apps.&lt;/p&gt;

&lt;p&gt;Your terminal stays visible, but it is excluded from screenshots. This prevents Claude from seeing its own prompts on screen.&lt;/p&gt;

&lt;p&gt;When Claude finishes a turn, hidden apps restore automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  You can stop it immediately
&lt;/h3&gt;

&lt;p&gt;When Claude acquires the lock, macOS shows a notification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Claude is using your computer - press Esc to stop.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can stop computer use in either of these ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Press &lt;code&gt;Esc&lt;/code&gt; from anywhere&lt;/li&gt;
&lt;li&gt;Press &lt;code&gt;Ctrl+C&lt;/code&gt; in the terminal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Claude releases the lock, restores hidden apps, and returns control to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Per-app approval
&lt;/h2&gt;

&lt;p&gt;Enabling &lt;code&gt;computer-use&lt;/code&gt; does not give Claude access to every app.&lt;/p&gt;

&lt;p&gt;The first time Claude needs a specific app in a session, Claude Code shows a terminal approval prompt with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which apps Claude wants to control&lt;/li&gt;
&lt;li&gt;Any extra permissions requested, such as clipboard access&lt;/li&gt;
&lt;li&gt;How many other apps will hide while Claude works&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can choose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Allow for this session&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deny&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Approvals last only for the current session. You approve apps again in the next session.&lt;/p&gt;

&lt;h3&gt;
  
  
  Apps with extra warnings
&lt;/h3&gt;

&lt;p&gt;Some app categories show additional warnings because they grant broad access.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Warning&lt;/th&gt;
&lt;th&gt;Apps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Equivalent to shell access&lt;/td&gt;
&lt;td&gt;Terminal, iTerm2, VS Code, Warp, other terminals and IDEs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can read or write any file&lt;/td&gt;
&lt;td&gt;Finder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can change system settings&lt;/td&gt;
&lt;td&gt;System Settings&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These apps are not blocked automatically. The warning exists so you can decide whether the task needs that level of access.&lt;/p&gt;

&lt;h3&gt;
  
  
  App control tiers
&lt;/h3&gt;

&lt;p&gt;Claude’s control level depends on the app category.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Control level&lt;/th&gt;
&lt;th&gt;App types&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;View-only&lt;/td&gt;
&lt;td&gt;Browsers, trading platforms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Click-only&lt;/td&gt;
&lt;td&gt;Terminals, IDEs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full control&lt;/td&gt;
&lt;td&gt;All other apps&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Browsers are view-only because they can expose account data and sensitive information. If you need full browser automation, use Claude in Chrome instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Claude decides when to use computer use
&lt;/h2&gt;

&lt;p&gt;Computer use is Claude’s last resort.&lt;/p&gt;

&lt;p&gt;Claude chooses the most precise available tool first:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;MCP server for the service, if configured&lt;/li&gt;
&lt;li&gt;Bash for shell commands&lt;/li&gt;
&lt;li&gt;Claude in Chrome for browser tasks, if configured&lt;/li&gt;
&lt;li&gt;Computer use when no programmatic interface can reach the target&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, if you ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Run the tests.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude should use a shell command such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should not click a UI button unless the target workflow requires GUI interaction.&lt;/p&gt;

&lt;p&gt;Use computer use for tasks like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Native desktop app validation&lt;/li&gt;
&lt;li&gt;iOS Simulator flows&lt;/li&gt;
&lt;li&gt;GUI-only tools&lt;/li&gt;
&lt;li&gt;Visual bug reproduction&lt;/li&gt;
&lt;li&gt;App interactions without a CLI or API&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Safety model
&lt;/h2&gt;

&lt;p&gt;Computer use runs on your real desktop. That is different from Claude’s sandboxed Bash tool.&lt;/p&gt;

&lt;p&gt;The Bash tool runs in an isolated environment with limited filesystem and network access. Computer use can interact with apps on your actual machine, depending on what you approve.&lt;/p&gt;

&lt;p&gt;Anthropic built several guardrails into the feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  Per-app approval
&lt;/h3&gt;

&lt;p&gt;Claude can only control apps you explicitly allow in the current session.&lt;/p&gt;

&lt;p&gt;There is no blanket machine-wide approval.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sentinel warnings
&lt;/h3&gt;

&lt;p&gt;Apps that expose shell access, filesystem access, or system settings changes are flagged before approval.&lt;/p&gt;

&lt;p&gt;This helps you understand what level of access you are granting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terminal excluded from screenshots
&lt;/h3&gt;

&lt;p&gt;Claude does not see your terminal window in screenshots.&lt;/p&gt;

&lt;p&gt;This prevents on-screen terminal prompts from being fed back into the model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Global escape
&lt;/h3&gt;

&lt;p&gt;Pressing &lt;code&gt;Esc&lt;/code&gt; aborts computer use from anywhere.&lt;/p&gt;

&lt;p&gt;The key press is consumed by Claude Code, so prompt injection attacks cannot use it to dismiss dialogs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lock file
&lt;/h3&gt;

&lt;p&gt;Only one Claude Code session can control your screen at a time.&lt;/p&gt;

&lt;p&gt;This prevents concurrent computer use sessions from competing for the same machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompt injection detection
&lt;/h3&gt;

&lt;p&gt;Claude checks actions and flags on-screen content that appears to be an attempt to redirect its behavior.&lt;/p&gt;

&lt;p&gt;Anthropic’s guidance is to avoid sensitive workflows until you are comfortable with how computer use behaves on your machine. Start with sandboxed apps, test environments, and non-sensitive data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example workflows
&lt;/h2&gt;

&lt;h3&gt;
  
  
  End-to-end Swift app validation
&lt;/h3&gt;

&lt;p&gt;Prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build the MenuBarStats target, launch it, open the preferences window,
and verify the interval slider updates the label. Screenshot the
preferences window when done.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected Claude workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;xcodebuild&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Launch the app&lt;/li&gt;
&lt;li&gt;Open the preferences window&lt;/li&gt;
&lt;li&gt;Move the interval slider&lt;/li&gt;
&lt;li&gt;Verify that the label updates&lt;/li&gt;
&lt;li&gt;Capture a screenshot&lt;/li&gt;
&lt;li&gt;Report failures with source locations&lt;/li&gt;
&lt;li&gt;Patch and re-test if needed&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Reproduce a layout bug
&lt;/h3&gt;

&lt;p&gt;Prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The settings modal clips its footer on narrow windows. Resize the app
window down until you can reproduce it, screenshot the clipped state,
then check the CSS for the modal container.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected Claude workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Resize the window in increments&lt;/li&gt;
&lt;li&gt;Capture the clipped state&lt;/li&gt;
&lt;li&gt;Inspect &lt;code&gt;modal.css&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Identify the overflow issue&lt;/li&gt;
&lt;li&gt;Apply a layout fix&lt;/li&gt;
&lt;li&gt;Re-test at the failing size&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Test an iOS Simulator flow without XCTest
&lt;/h3&gt;

&lt;p&gt;Prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Open the iOS Simulator, launch the app, tap through the onboarding
screens, and tell me if any screen takes more than a second to load.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude controls the Simulator through the GUI. You do not need to create XCTest targets, UI test selectors, or Instruments configuration for this exploratory pass.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validate an Electron onboarding flow
&lt;/h3&gt;

&lt;p&gt;Prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Launch the desktop app in dev mode, complete the signup flow using
test@example.com, and screenshot each step. Flag any step where the
button is not clickable or the UI shows an error.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start the app&lt;/li&gt;
&lt;li&gt;Fill form fields&lt;/li&gt;
&lt;li&gt;Click through each onboarding screen&lt;/li&gt;
&lt;li&gt;Capture screenshots&lt;/li&gt;
&lt;li&gt;Report blocked buttons or UI errors&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Using computer use with API testing
&lt;/h2&gt;

&lt;p&gt;Claude Code computer use pairs well with Apidog for full-stack API verification.&lt;/p&gt;

&lt;p&gt;A practical workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Claude writes or updates a local server.&lt;/li&gt;
&lt;li&gt;Claude builds and launches the app.&lt;/li&gt;
&lt;li&gt;Claude uses computer use to trigger a user action in the UI.&lt;/li&gt;
&lt;li&gt;You capture or inspect the underlying API call in Apidog.&lt;/li&gt;
&lt;li&gt;You create an automated API test for the same request.&lt;/li&gt;
&lt;li&gt;Future regressions are caught by the API test instead of manual UI validation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This gives you two layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude validates the user-facing flow through the GUI.&lt;/li&gt;
&lt;li&gt;Apidog validates the underlying API behavior programmatically.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The GUI pass confirms the happy path. The API test guards that behavior going forward, including in CI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Differences between CLI and Desktop app
&lt;/h2&gt;

&lt;p&gt;The CLI and Desktop app use the same computer use engine, but some settings are Desktop-only for now.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Desktop&lt;/th&gt;
&lt;th&gt;CLI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Enable&lt;/td&gt;
&lt;td&gt;Settings &amp;gt; Desktop app &amp;gt; General&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;/mcp&lt;/code&gt; &amp;gt; enable &lt;code&gt;computer-use&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Denied apps list&lt;/td&gt;
&lt;td&gt;Configurable in Settings&lt;/td&gt;
&lt;td&gt;Not available yet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto-unhide toggle&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;td&gt;Always on&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dispatch integration&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Not applicable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For most development workflows, the CLI version covers the core computer use flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;h3&gt;
  
  
  “Computer use is in use by another Claude session”
&lt;/h3&gt;

&lt;p&gt;Another Claude Code session holds the machine lock.&lt;/p&gt;

&lt;p&gt;Fix:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Exit the other session.&lt;/li&gt;
&lt;li&gt;If it crashed, wait for Claude Code to detect that the process is gone.&lt;/li&gt;
&lt;li&gt;Retry the computer use request.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  macOS permissions prompt keeps reappearing
&lt;/h3&gt;

&lt;p&gt;macOS may require a process restart after granting Screen Recording.&lt;/p&gt;

&lt;p&gt;Fix:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Quit Claude Code completely.&lt;/li&gt;
&lt;li&gt;Start a new Claude Code session.&lt;/li&gt;
&lt;li&gt;Open &lt;strong&gt;System Settings &amp;gt; Privacy &amp;amp; Security &amp;gt; Screen Recording&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Confirm your terminal emulator is listed and enabled.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Also check &lt;strong&gt;Accessibility&lt;/strong&gt; permissions in the same Privacy &amp;amp; Security area.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;computer-use&lt;/code&gt; does not appear in &lt;code&gt;/mcp&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Check the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You are on macOS.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;claude --version&lt;/code&gt; shows &lt;code&gt;v2.1.85&lt;/code&gt; or later.&lt;/li&gt;
&lt;li&gt;You are on a Pro or Max plan.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/status&lt;/code&gt; confirms the expected account.&lt;/li&gt;
&lt;li&gt;You are authenticated through &lt;code&gt;claude.ai&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You are not using Bedrock, Vertex AI, or another third-party provider.&lt;/li&gt;
&lt;li&gt;You are in an interactive session.&lt;/li&gt;
&lt;li&gt;You are not using the &lt;code&gt;-p&lt;/code&gt; flag.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Claude cannot see the app after approval
&lt;/h3&gt;

&lt;p&gt;Make sure you selected &lt;strong&gt;Allow for this session&lt;/strong&gt; in the per-app approval prompt.&lt;/p&gt;

&lt;p&gt;If you accidentally denied the app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Exit the Claude Code session.&lt;/li&gt;
&lt;li&gt;Start a new session.&lt;/li&gt;
&lt;li&gt;Retry the task.&lt;/li&gt;
&lt;li&gt;Approve the app when prompted.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Approvals and denials reset each session.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Which Claude Code version do I need?
&lt;/h3&gt;

&lt;p&gt;You need Claude Code &lt;code&gt;v2.1.85&lt;/code&gt; or later.&lt;/p&gt;

&lt;p&gt;Check your version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update if needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @anthropic-ai/claude-code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Does it work on Windows or Linux?
&lt;/h3&gt;

&lt;p&gt;No. Computer use is macOS-only in the current research preview.&lt;/p&gt;

&lt;p&gt;Anthropic has not announced a timeline for Windows or Linux support.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use computer use through Amazon Bedrock or Google Vertex AI?
&lt;/h3&gt;

&lt;p&gt;No. Computer use requires authentication through a &lt;code&gt;claude.ai&lt;/code&gt; account on a Pro or Max plan.&lt;/p&gt;

&lt;p&gt;Third-party providers such as Amazon Bedrock, Google Vertex AI, and Microsoft Foundry do not support this feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is it available on Team or Enterprise plans?
&lt;/h3&gt;

&lt;p&gt;No. During the research preview, it is available only on Pro and Max plans.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens if I do not grant Screen Recording permission?
&lt;/h3&gt;

&lt;p&gt;Claude may still click and type if Accessibility is granted, but it cannot verify visual results without Screen Recording.&lt;/p&gt;

&lt;p&gt;Most useful computer use workflows require both permissions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can Claude access apps I did not approve?
&lt;/h3&gt;

&lt;p&gt;No. Claude can only control apps you explicitly approve in the current session.&lt;/p&gt;

&lt;p&gt;The approval prompt appears the first time Claude needs each app.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I revoke computer use access completely?
&lt;/h3&gt;

&lt;p&gt;Disable the MCP server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then disable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;computer-use
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To remove macOS permissions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;System Settings &amp;gt; Privacy &amp;amp; Security&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Remove your terminal app from &lt;strong&gt;Accessibility&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Remove your terminal app from &lt;strong&gt;Screen Recording&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Is computer use safe for sensitive work?
&lt;/h3&gt;

&lt;p&gt;Anthropic recommends avoiding sensitive data during the research preview.&lt;/p&gt;

&lt;p&gt;Start with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Isolated test environments&lt;/li&gt;
&lt;li&gt;Local development apps&lt;/li&gt;
&lt;li&gt;Non-production accounts&lt;/li&gt;
&lt;li&gt;Non-sensitive datasets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Review Anthropic’s computer use safety guidance before using it with credentials, personal data, production systems, or regulated workflows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can multiple Claude Code sessions use computer use at the same time?
&lt;/h3&gt;

&lt;p&gt;No. Computer use holds a machine-wide lock.&lt;/p&gt;

&lt;p&gt;Only one Claude Code session can control your screen at a time. If another session holds the lock, Claude Code shows an error with the session details.&lt;/p&gt;

&lt;h3&gt;
  
  
  How is this different from Playwright or Selenium?
&lt;/h3&gt;

&lt;p&gt;Playwright and Selenium are scripted test frameworks. They require selectors, assertions, configuration, and test maintenance.&lt;/p&gt;

&lt;p&gt;Computer use lets Claude interact with an app through natural language, without a test harness.&lt;/p&gt;

&lt;p&gt;Use computer use for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exploratory testing&lt;/li&gt;
&lt;li&gt;Quick UI validation&lt;/li&gt;
&lt;li&gt;Visual bug reproduction&lt;/li&gt;
&lt;li&gt;GUI-only tools&lt;/li&gt;
&lt;li&gt;Apps that do not expose automation APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use Playwright, Selenium, XCTest, or similar tools for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deterministic regression tests&lt;/li&gt;
&lt;li&gt;CI pipelines&lt;/li&gt;
&lt;li&gt;Repeatable production test coverage&lt;/li&gt;
&lt;li&gt;Complex assertions&lt;/li&gt;
&lt;li&gt;Long-term test suites&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Computer use is faster to start. Scripted tests are more reliable over time.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Use Qwen3.5-Omni: Text, Audio, Video, and Voice Cloning via API</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Wed, 24 Jun 2026 01:03:30 +0000</pubDate>
      <link>https://dev.to/preecha/how-to-use-qwen35-omni-text-audio-video-and-voice-cloning-via-api-3h8j</link>
      <guid>https://dev.to/preecha/how-to-use-qwen35-omni-text-audio-video-and-voice-cloning-via-api-3h8j</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Qwen3.5-Omni accepts text, images, audio, and video as input and returns text or real-time speech. You can access it through the Alibaba Cloud DashScope API or run it locally with HuggingFace Transformers. This guide walks through API setup, working examples for each modality, voice cloning, streaming, local deployment, retries, and testing with Apidog.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What you’re working with
&lt;/h2&gt;

&lt;p&gt;Qwen3.5-Omni is a single multimodal model that handles four input types in one request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text&lt;/li&gt;
&lt;li&gt;Images&lt;/li&gt;
&lt;li&gt;Audio&lt;/li&gt;
&lt;li&gt;Video&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It can return either text or natural speech, depending on your request configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffafib4wwd0lg6zpbrixn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffafib4wwd0lg6zpbrixn.png" alt="Image" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Released March 30, 2026, Qwen3.5-Omni uses a Thinker-Talker architecture with an MoE backbone:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Thinker&lt;/strong&gt;: processes multimodal input and performs reasoning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Talker&lt;/strong&gt;: converts output into speech using a multi-codebook system that can start streaming audio before the full response is complete.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Available variants:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variant&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Plus&lt;/td&gt;
&lt;td&gt;Highest quality, reasoning, voice cloning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flash&lt;/td&gt;
&lt;td&gt;Balanced speed and quality for most production use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Light&lt;/td&gt;
&lt;td&gt;Lowest latency for mobile and edge scenarios&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Most examples below use &lt;code&gt;qwen3.5-omni-flash&lt;/code&gt;. Use &lt;code&gt;qwen3.5-omni-plus&lt;/code&gt; when quality matters most, and &lt;code&gt;qwen3.5-omni-light&lt;/code&gt; when latency is the main constraint.&lt;/p&gt;

&lt;h2&gt;
  
  
  API access via DashScope
&lt;/h2&gt;

&lt;p&gt;Alibaba Cloud DashScope is the primary hosted API for Qwen3.5-Omni. You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A DashScope account&lt;/li&gt;
&lt;li&gt;A DashScope API key&lt;/li&gt;
&lt;li&gt;Either the DashScope SDK or the OpenAI-compatible API endpoint&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Create a DashScope account
&lt;/h3&gt;

&lt;p&gt;Go to &lt;code&gt;dashscope.aliyuncs.com&lt;/code&gt; and sign up. If you already have an Alibaba Cloud account, use that account.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create an API key
&lt;/h3&gt;

&lt;p&gt;In the DashScope console:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;API Key Management&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create API Key&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Copy the key.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key format starts with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sk-...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Install an SDK
&lt;/h3&gt;

&lt;p&gt;Install the DashScope SDK:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;dashscope
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use the OpenAI Python SDK with DashScope’s OpenAI-compatible endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;openai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DashScope exposes an OpenAI-compatible API at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://dashscope.aliyuncs.com/compatible-mode/v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That means you can reuse OpenAI-style chat completion code by changing &lt;code&gt;base_url&lt;/code&gt; and &lt;code&gt;api_key&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Text input and output
&lt;/h2&gt;

&lt;p&gt;Start with the simplest request: text in, text out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dashscope.aliyuncs.com/compatible-mode/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-YOUR_DASHSCOPE_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3.5-omni-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Explain the difference between REST and GraphQL APIs in plain terms.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use a different model ID when needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3.5-omni-plus&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;   &lt;span class="c1"&gt;# better quality
&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3.5-omni-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# balanced default
&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3.5-omni-light&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# lower latency
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Audio input: transcription and understanding
&lt;/h2&gt;

&lt;p&gt;You can send audio as a URL or as base64-encoded data. The model can transcribe and reason over the audio directly, so you do not need a separate ASR step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dashscope.aliyuncs.com/compatible-mode/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-YOUR_DASHSCOPE_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;meeting_recording.wav&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;audio_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3.5-omni-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;audio_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;format&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wav&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Summarize the key decisions made in this meeting and list any action items.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Qwen3.5-Omni handles 113 languages for speech recognition and detects the language automatically.&lt;/p&gt;

&lt;p&gt;Supported audio formats include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WAV&lt;/li&gt;
&lt;li&gt;MP3&lt;/li&gt;
&lt;li&gt;M4A&lt;/li&gt;
&lt;li&gt;OGG&lt;/li&gt;
&lt;li&gt;FLAC&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Audio output: text-to-speech response
&lt;/h2&gt;

&lt;p&gt;To receive speech in the response, set &lt;code&gt;modalities&lt;/code&gt; and configure the &lt;code&gt;audio&lt;/code&gt; output.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dashscope.aliyuncs.com/compatible-mode/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-YOUR_DASHSCOPE_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3.5-omni-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;modalities&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;audio&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;voice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Chelsie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;format&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wav&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Describe the steps to authenticate a REST API using OAuth 2.0.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;text_content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
&lt;span class="n"&gt;audio_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response.wav&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audio_data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Text: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;text_content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Audio saved to response.wav&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Built-in voices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Chelsie&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Ethan&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Speech generation works in 36 languages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Image input: visual understanding
&lt;/h2&gt;

&lt;p&gt;Send an image URL with a text prompt when you want the model to inspect visual content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dashscope.aliyuncs.com/compatible-mode/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-YOUR_DASHSCOPE_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3.5-omni-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://example.com/api-diagram.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Describe this API architecture diagram and identify any potential bottlenecks.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For local images, encode the file as base64 and pass it as a data URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dashscope.aliyuncs.com/compatible-mode/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-YOUR_DASHSCOPE_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;screenshot.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;image_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;image_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data:image/png;base64,&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;image_data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3.5-omni-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;image_url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What error is shown in this screenshot?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Video input: understand recordings and screen captures
&lt;/h2&gt;

&lt;p&gt;Video input lets Qwen3.5-Omni reason across visual frames and audio tracks in one request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dashscope.aliyuncs.com/compatible-mode/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-YOUR_DASHSCOPE_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3.5-omni-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;video_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;video_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://example.com/product-demo.mp4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Describe what the developer is building in this demo and write equivalent code.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Audio-Visual Vibe Coding
&lt;/h3&gt;

&lt;p&gt;A common workflow is to pass a screen recording and ask the model to generate code from what it sees.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dashscope.aliyuncs.com/compatible-mode/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-YOUR_DASHSCOPE_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;screen_recording.mp4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;video_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3.5-omni-plus&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;video_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;video_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data:video/mp4;base64,&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;video_data&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Watch this screen recording and write the complete code that replicates what you see being built. Include all the UI components and their interactions.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The 256K token context window fits roughly 400 seconds of 720p video with audio. For longer recordings, trim or split the video before sending it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Voice cloning
&lt;/h2&gt;

&lt;p&gt;Voice cloning lets you provide a target voice sample and have the model respond in that voice. This is available through the API on Plus and Flash.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dashscope.aliyuncs.com/compatible-mode/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-YOUR_DASHSCOPE_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;voice_sample.wav&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;voice_sample&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3.5-omni-plus&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;modalities&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;audio&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;voice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;custom&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;format&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wav&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;voice_sample&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;voice_sample&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;format&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wav&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Welcome to the Apidog developer portal. How can I help you today?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;audio_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cloned_response.wav&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audio_data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For better voice cloning quality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a clean recording with minimal background noise.&lt;/li&gt;
&lt;li&gt;Prefer 15-30 seconds of speech.&lt;/li&gt;
&lt;li&gt;Use WAV at 16kHz or higher.&lt;/li&gt;
&lt;li&gt;Use natural speech instead of read-aloud text when possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Streaming responses
&lt;/h2&gt;

&lt;p&gt;For real-time voice chat or interactive apps, use streaming. The model can start returning audio before the full response is complete.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dashscope.aliyuncs.com/compatible-mode/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-YOUR_DASHSCOPE_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3.5-omni-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;modalities&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;audio&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;voice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ethan&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;format&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pcm16&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Explain how WebSocket connections differ from HTTP polling.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;audio_chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;text_chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;audio_chunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;text_chunks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;audio_chunks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;full_audio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;audio_chunks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;streamed_response.pcm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;full_audio&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;pcm16&lt;/code&gt; is useful for streaming because you can pipe chunks directly into an audio output buffer without waiting for a complete file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-turn conversation with mixed modalities
&lt;/h2&gt;

&lt;p&gt;You can keep conversation state across turns and mix modalities as needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dashscope.aliyuncs.com/compatible-mode/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-YOUR_DASHSCOPE_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;conversation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content_parts&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;content_parts&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3.5-omni-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
    &lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;assistant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;

&lt;span class="c1"&gt;# Turn 1: text
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I have an API that keeps returning 503 errors.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]))&lt;/span&gt;

&lt;span class="c1"&gt;# Turn 2: image + text
&lt;/span&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error_log.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data:image/png;base64,&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Here&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s the error log screenshot. What&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s causing this?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]))&lt;/span&gt;

&lt;span class="c1"&gt;# Turn 3: follow-up text
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;send_message&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How do I fix the connection pool exhaustion you mentioned?&lt;/span&gt;&lt;span class="sh"&gt;"&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;The 256K context window supports long conversations, including conversations with images and audio in the history.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local deployment with HuggingFace
&lt;/h2&gt;

&lt;p&gt;To run Qwen3.5-Omni on your own infrastructure, install the required packages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;&lt;span class="nv"&gt;transformers&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;4.57.3
pip &lt;span class="nb"&gt;install &lt;/span&gt;accelerate
pip &lt;span class="nb"&gt;install &lt;/span&gt;qwen-omni-utils &lt;span class="nt"&gt;-U&lt;/span&gt;
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-U&lt;/span&gt; flash-attn &lt;span class="nt"&gt;--no-build-isolation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then load the model and processor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;soundfile&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;sf&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Qwen3OmniMoeForConditionalGeneration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Qwen3OmniMoeProcessor&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;qwen_omni_utils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;process_mm_info&lt;/span&gt;

&lt;span class="n"&gt;model_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Qwen/Qwen3-Omni-30B-A3B-Instruct&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Qwen3OmniMoeForConditionalGeneration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;device_map&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auto&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;attn_implementation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flash_attention_2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;processor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Qwen3OmniMoeProcessor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;conversation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;system&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are Qwen, a virtual human developed by the Qwen Team, Alibaba Group, capable of perceiving auditory and visual inputs, as well as generating text and speech.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;path/to/your/audio.wav&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What is being discussed in this audio?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply_chat_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;add_generation_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tokenize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;audios&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;videos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;process_mm_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;use_audio_in_video&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;audio&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;audios&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;videos&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;videos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;return_tensors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;text_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;audio_output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;speaker&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Chelsie&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;text_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;batch_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;text_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;skip_special_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;sf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;local_response.wav&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;audio_output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reshape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;numpy&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;samplerate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;24000&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text_response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Approximate GPU memory requirements:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variant&lt;/th&gt;
&lt;th&gt;Precision&lt;/th&gt;
&lt;th&gt;Min VRAM&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Plus / 30B MoE&lt;/td&gt;
&lt;td&gt;BF16&lt;/td&gt;
&lt;td&gt;~40GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flash&lt;/td&gt;
&lt;td&gt;BF16&lt;/td&gt;
&lt;td&gt;~20GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Light&lt;/td&gt;
&lt;td&gt;BF16&lt;/td&gt;
&lt;td&gt;~10GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For production local inference, use vLLM instead of HuggingFace Transformers. MoE models run faster with vLLM routing optimizations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Qwen3.5-Omni requests with Apidog
&lt;/h2&gt;

&lt;p&gt;Multimodal API requests are harder to debug than plain JSON. You may need to inspect base64-encoded media, nested content arrays, and responses that include both text and audio.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffafib4wwd0lg6zpbrixn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffafib4wwd0lg6zpbrixn.png" alt="Image" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A practical workflow in Apidog:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new collection for DashScope.&lt;/li&gt;
&lt;li&gt;Set the base URL to:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   https://dashscope.aliyuncs.com/compatible-mode/v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Store your DashScope API key as an environment variable.&lt;/li&gt;
&lt;li&gt;Create request templates for each modality:

&lt;ul&gt;
&lt;li&gt;Text&lt;/li&gt;
&lt;li&gt;Audio input&lt;/li&gt;
&lt;li&gt;Audio output&lt;/li&gt;
&lt;li&gt;Image input&lt;/li&gt;
&lt;li&gt;Video input&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Duplicate the base request for &lt;code&gt;Plus&lt;/code&gt;, &lt;code&gt;Flash&lt;/code&gt;, and &lt;code&gt;Light&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Change only the &lt;code&gt;model&lt;/code&gt; parameter to compare output quality and latency.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can also add test assertions for response validation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verify &lt;code&gt;choices[0].message.content&lt;/code&gt; is not empty for text responses.&lt;/li&gt;
&lt;li&gt;Verify &lt;code&gt;choices[0].message.audio.data&lt;/code&gt; exists when audio output is requested.&lt;/li&gt;
&lt;li&gt;Assert that Flash latency stays under your target threshold.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This helps you choose the right model variant before building the full application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error handling and retry logic
&lt;/h2&gt;

&lt;p&gt;Large multimodal requests can hit rate limits, connection errors, or timeouts. Add retries from the start.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RateLimitError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;APITimeoutError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;APIConnectionError&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dashscope.aliyuncs.com/compatible-mode/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-YOUR_DASHSCOPE_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call_with_retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qwen3.5-omni-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_retries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_retries&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;RateLimitError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Rate limit hit. Waiting &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;except &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;APITimeoutError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;APIConnectionError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;max_retries&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;raise&lt;/span&gt;

            &lt;span class="n"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Connection error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. Retrying in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed after &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;max_retries&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; attempts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For video inputs larger than 100MB:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trim to the relevant section.&lt;/li&gt;
&lt;li&gt;Reduce resolution to 480p when high visual detail is not required.&lt;/li&gt;
&lt;li&gt;Split long recordings into segments and aggregate the results in your app.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common issues and fixes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Audio output is garbled on numbers or technical terms
&lt;/h3&gt;

&lt;p&gt;This is the problem ARIA technology addresses. Make sure you are using Qwen3.5-Omni, not an earlier version. If you self-host, use the latest model weights from HuggingFace.&lt;/p&gt;

&lt;h3&gt;
  
  
  The model keeps talking when I send an audio interruption
&lt;/h3&gt;

&lt;p&gt;Semantic interruption requires Flash or Plus. Light may not support this feature. Also make sure you are streaming the response instead of using a batch request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Voice cloning quality is poor
&lt;/h3&gt;

&lt;p&gt;Use a cleaner voice sample. Remove background noise with a tool such as Audacity before uploading. Use at least 15 seconds of audio. WAV at 16kHz or 44.1kHz works best.&lt;/p&gt;

&lt;h3&gt;
  
  
  Video input returns a token limit error
&lt;/h3&gt;

&lt;p&gt;The 256K token context covers roughly 400 seconds of 720p video. For longer videos, trim the clip or lower the resolution. Keep videos under about 6 minutes for a safer margin.&lt;/p&gt;

&lt;h3&gt;
  
  
  Local deployment is very slow
&lt;/h3&gt;

&lt;p&gt;Use vLLM instead of HuggingFace Transformers for production local inference. MoE models need vLLM routing optimizations for better throughput.&lt;/p&gt;

&lt;p&gt;For developers whose primary need is high-fidelity speech synthesis rather than full multimodal inference, Fish Audio S2's dedicated TTS and voice-cloning API offers a narrower, faster endpoint worth evaluating alongside all-in-one multimodal models.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Which DashScope model ID should I use for Qwen3.5-Omni?
&lt;/h3&gt;

&lt;p&gt;Use one of these:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;qwen3.5-omni-plus
qwen3.5-omni-flash
qwen3.5-omni-light
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start with &lt;code&gt;qwen3.5-omni-flash&lt;/code&gt; for most use cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use the OpenAI Python SDK with DashScope?
&lt;/h3&gt;

&lt;p&gt;Yes. Configure the client like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dashscope.aliyuncs.com/compatible-mode/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sk-YOUR_DASHSCOPE_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&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;The request and response format follows the OpenAI-compatible API style.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I send multiple files, such as audio and image, in one request?
&lt;/h3&gt;

&lt;p&gt;Put each file in the &lt;code&gt;content&lt;/code&gt; array as a separate typed object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input_audio&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;audio_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;format&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wav&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;image_url&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Use the audio and image to explain what is happening.&lt;/span&gt;&lt;span class="sh"&gt;"&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;All four modalities can appear in the same message.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is there a size limit for audio or video files?
&lt;/h3&gt;

&lt;p&gt;DashScope has per-request payload limits. For large files, use a URL reference instead of base64 encoding. Host the file on accessible storage and pass the URL in the audio or &lt;code&gt;video_url&lt;/code&gt; field.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I disable audio output and get text only?
&lt;/h3&gt;

&lt;p&gt;Omit &lt;code&gt;modalities&lt;/code&gt;, or set it to text only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;modalities&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Text-only responses are faster and cheaper.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Qwen3.5-Omni support function calling?
&lt;/h3&gt;

&lt;p&gt;Yes. Use the standard &lt;code&gt;tools&lt;/code&gt; parameter with function definitions, the same way you would with other OpenAI-compatible models. The model returns structured tool call objects that your application executes.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the best way to handle long audio recordings?
&lt;/h3&gt;

&lt;p&gt;For recordings under 10 hours, send them as a single request. For longer recordings, split at natural pause points, process each segment, and aggregate the results in your application layer.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I test multimodal requests before building a full application?
&lt;/h3&gt;

&lt;p&gt;Use Apidog to build saved request templates for each modality, switch between model variants, inspect the full response structure, and write assertions before integrating the API into your application.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Qwen3.5-Omni Is Here: Alibaba's Omnimodal AI Beats Gemini on Audio</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Tue, 23 Jun 2026 13:03:20 +0000</pubDate>
      <link>https://dev.to/preecha/qwen35-omni-is-here-alibabas-omnimodal-ai-beats-gemini-on-audio-4af6</link>
      <guid>https://dev.to/preecha/qwen35-omni-is-here-alibabas-omnimodal-ai-beats-gemini-on-audio-4af6</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Alibaba released Qwen3.5-Omni on March 30, 2026. It processes text, images, audio, and video in a single model and outputs both text and real-time speech. It outperforms Gemini 3.1 Pro on general audio understanding and reasoning benchmarks, supports 113 languages for speech recognition, and includes voice cloning. Three variants are available: Plus, Flash, and Light.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Qwen3.5-Omni matters for developers
&lt;/h2&gt;

&lt;p&gt;Most multimodal AI apps are still built as pipelines:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Speech-to-text for audio input&lt;/li&gt;
&lt;li&gt;Vision model for images or video frames&lt;/li&gt;
&lt;li&gt;LLM for reasoning and response generation&lt;/li&gt;
&lt;li&gt;Text-to-speech for voice output&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That architecture works, but every handoff adds latency, cost, and failure points.&lt;/p&gt;

&lt;p&gt;Qwen3.5-Omni collapses that stack into one model. It accepts text, images, audio, and video as input, then returns text or speech as output from a single inference call.&lt;/p&gt;

&lt;p&gt;The model supports a 256,000-token context window, which can fit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;More than 10 hours of audio&lt;/li&gt;
&lt;li&gt;Roughly 400 seconds of 720p video with audio&lt;/li&gt;
&lt;li&gt;Around 190,000 words of text&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alibaba trained it on more than 100 million hours of native audio-visual data. The practical result: you can build applications where the model reasons across speech, visuals, and text together instead of stitching together separate model outputs.&lt;/p&gt;

&lt;p&gt;Use cases include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Voice assistants&lt;/li&gt;
&lt;li&gt;Video analysis tools&lt;/li&gt;
&lt;li&gt;Multilingual support agents&lt;/li&gt;
&lt;li&gt;Accessibility tools&lt;/li&gt;
&lt;li&gt;Developer productivity workflows using screen recordings&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What changed from Qwen3-Omni
&lt;/h2&gt;

&lt;p&gt;The previous generation, Qwen3-Omni Flash, launched in December 2025 with 234ms response latency. Qwen3.5-Omni is the next full release.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qqnoy7jlzgxo1nhfduf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3qqnoy7jlzgxo1nhfduf.png" alt="Image" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Speech recognition now covers 113 languages
&lt;/h3&gt;

&lt;p&gt;Qwen3-Omni supported speech recognition in 19 languages. Qwen3.5-Omni expands that to 113 languages and dialects.&lt;/p&gt;

&lt;p&gt;Speech generation also increased from 10 languages to 36.&lt;/p&gt;

&lt;p&gt;For developers, this matters if your app needs to support users outside major Western markets. Instead of routing different languages through separate ASR vendors, you can test one model across a much broader language set.&lt;/p&gt;

&lt;p&gt;Example workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transcribe customer support calls in multiple languages&lt;/li&gt;
&lt;li&gt;Summarize non-English podcasts or interviews&lt;/li&gt;
&lt;li&gt;Handle bilingual conversations with mid-sentence language switching&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Voice cloning is available through the API
&lt;/h3&gt;

&lt;p&gt;Qwen3.5-Omni Plus and Flash support voice cloning through the API.&lt;/p&gt;

&lt;p&gt;The workflow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upload or reference a voice sample&lt;/li&gt;
&lt;li&gt;Send the user prompt and voice configuration&lt;/li&gt;
&lt;li&gt;Receive speech output in the cloned voice&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistent voice personas&lt;/li&gt;
&lt;li&gt;Branded voice agents&lt;/li&gt;
&lt;li&gt;Long-running conversational assistants&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Voice cloning was not available in the previous generation.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. ARIA improves pronunciation for numbers and technical terms
&lt;/h3&gt;

&lt;p&gt;Neural TTS systems often struggle with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Product names&lt;/li&gt;
&lt;li&gt;Technical terms&lt;/li&gt;
&lt;li&gt;Proper nouns&lt;/li&gt;
&lt;li&gt;Prices&lt;/li&gt;
&lt;li&gt;Version numbers&lt;/li&gt;
&lt;li&gt;Acronyms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Qwen3.5-Omni introduces ARIA, a dynamic text-speech synchronization layer. It reads ahead in the text buffer and adjusts phoneme generation before audio is emitted.&lt;/p&gt;

&lt;p&gt;That helps terms like these render correctly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IPv6
$249.99
Qwen3.5-Omni
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is especially relevant for developer tools, sales assistants, support bots, and technical documentation readers.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Semantic interruption improves voice UX
&lt;/h3&gt;

&lt;p&gt;In many voice systems, any incoming audio is treated as an interruption.&lt;/p&gt;

&lt;p&gt;That creates bad UX:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User says “uh-huh” → assistant stops&lt;/li&gt;
&lt;li&gt;User says “right” → assistant stops&lt;/li&gt;
&lt;li&gt;User says “wait, stop” → assistant should stop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Qwen3.5-Omni distinguishes between backchannels and real interruptions.&lt;/p&gt;

&lt;p&gt;This makes it more useful for real-time voice assistants where users naturally acknowledge, pause, or interrupt during conversation.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Real-time web search is integrated
&lt;/h3&gt;

&lt;p&gt;Qwen3.5-Omni can query the web during inference and include live results in its response.&lt;/p&gt;

&lt;p&gt;That means you do not always need to pre-fetch external context and inject it into the prompt yourself.&lt;/p&gt;

&lt;p&gt;Use this when your app needs current information, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recent documentation&lt;/li&gt;
&lt;li&gt;Current pricing&lt;/li&gt;
&lt;li&gt;News or market updates&lt;/li&gt;
&lt;li&gt;Live product information&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Screen recordings can become coding input
&lt;/h3&gt;

&lt;p&gt;Qwen3.5-Omni supports “Audio-Visual Vibe Coding.”&lt;/p&gt;

&lt;p&gt;The workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Record a screen interaction&lt;/li&gt;
&lt;li&gt;Send the video to the model&lt;/li&gt;
&lt;li&gt;Ask the model to replicate, explain, or improve what it sees&lt;/li&gt;
&lt;li&gt;Use the generated code as a starting point&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This gives coding assistants a new input format: video.&lt;/p&gt;

&lt;p&gt;Instead of describing UI behavior in text, you can provide a screen recording and ask for implementation guidance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmark results
&lt;/h2&gt;

&lt;p&gt;Across 36 audio and audio-visual benchmarks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Qwen3.5-Omni achieves state-of-the-art on 32 out of 36&lt;/li&gt;
&lt;li&gt;It sets new state-of-the-art on 22 of those 36&lt;/li&gt;
&lt;li&gt;It outperforms Gemini 3.1 Pro on general audio understanding, reasoning, and translation&lt;/li&gt;
&lt;li&gt;It matches Gemini 3.1 Pro on audio-visual comprehension&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For speech generation quality, Alibaba reports that Qwen3.5-Omni beats ElevenLabs, GPT-Audio, and Minimax on multilingual voice stability across 20 languages.&lt;/p&gt;

&lt;p&gt;That comparison is notable because ElevenLabs is a dedicated voice AI company. Still, you should benchmark against your own prompts, languages, accents, and audio conditions before choosing a production model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model variants
&lt;/h2&gt;

&lt;p&gt;Alibaba ships three versions.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variant&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Qwen3.5-Omni Plus&lt;/td&gt;
&lt;td&gt;Maximum quality; audio-visual reasoning, voice cloning, long-context tasks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen3.5-Omni Flash&lt;/td&gt;
&lt;td&gt;Balanced speed and quality; real-time voice chat, production APIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qwen3.5-Omni Light&lt;/td&gt;
&lt;td&gt;Low-latency tasks; mobile and edge scenarios&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;All three handle text, images, audio, and video as input.&lt;/p&gt;

&lt;p&gt;The differences are mainly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Output quality&lt;/li&gt;
&lt;li&gt;Latency&lt;/li&gt;
&lt;li&gt;Cost&lt;/li&gt;
&lt;li&gt;Deployment fit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most production APIs, start by testing Flash. Use Plus when quality matters more than latency or cost. Use Light for latency-sensitive scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working with the 256K token context window
&lt;/h2&gt;

&lt;p&gt;Qwen3.5-Omni supports up to 256,000 input tokens.&lt;/p&gt;

&lt;p&gt;In practice, that means you can send:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A long meeting recording&lt;/li&gt;
&lt;li&gt;A full support call&lt;/li&gt;
&lt;li&gt;A product demo video&lt;/li&gt;
&lt;li&gt;A large document&lt;/li&gt;
&lt;li&gt;Mixed text, audio, image, and video context&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Approximate capacity:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input type&lt;/th&gt;
&lt;th&gt;Approximate capacity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Audio&lt;/td&gt;
&lt;td&gt;More than 10 hours of continuous speech&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Video&lt;/td&gt;
&lt;td&gt;Roughly 400 seconds of 720p video with embedded audio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Text&lt;/td&gt;
&lt;td&gt;Around 190,000 words&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For many multimodal use cases, this removes the need to chunk inputs manually.&lt;/p&gt;

&lt;p&gt;Example prompt for a meeting recording:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Summarize this meeting recording.

Return:
1. Main decisions
2. Open questions
3. Action items with owners
4. Risks mentioned
5. Follow-up email draft
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example prompt for a product demo video:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Analyze this product demo video.

Return:
1. What feature is being demonstrated
2. Step-by-step user flow
3. Any visible bugs or UX friction
4. Suggested improvements
5. A short release note
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Qwen3.5-Omni’s 256K context is smaller than Gemini 2.5 Pro’s 1M context and larger than many standard multimodal workflows require. Compared with GPT-4o’s 128K context, it gives more room for long audio-visual inputs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building multilingual voice workflows
&lt;/h2&gt;

&lt;p&gt;The increase from 19 to 113 speech recognition languages changes how you can design multilingual systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customer support
&lt;/h3&gt;

&lt;p&gt;You can route voice input from many regions into the same model rather than maintaining separate ASR pipelines per language.&lt;/p&gt;

&lt;p&gt;Example support-agent prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a customer support assistant.

Input:
- Customer audio
- Product documentation
- Recent order information

Tasks:
1. Detect the spoken language
2. Transcribe the user request
3. Identify the issue
4. Reply in the same language
5. Escalate if the issue involves billing, legal, or account security
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Content processing
&lt;/h3&gt;

&lt;p&gt;For podcasts, interviews, and videos, one request can cover transcription, translation, and summarization.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Process this interview.

Return:
1. Original-language transcript
2. English translation
3. 5-bullet summary
4. Notable quotes
5. Speaker-by-speaker topic breakdown
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mid-conversation language switching
&lt;/h3&gt;

&lt;p&gt;Bilingual users often switch languages mid-sentence.&lt;/p&gt;

&lt;p&gt;Qwen3.5-Omni handles this natively, which is useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Support conversations&lt;/li&gt;
&lt;li&gt;Education apps&lt;/li&gt;
&lt;li&gt;Travel assistants&lt;/li&gt;
&lt;li&gt;Internal company tools for global teams&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture: Thinker-Talker with MoE
&lt;/h2&gt;

&lt;p&gt;Qwen3.5-Omni uses a Thinker-Talker architecture.&lt;/p&gt;

&lt;p&gt;The Thinker processes multimodal input and generates reasoning tokens.&lt;/p&gt;

&lt;p&gt;The Talker converts those tokens into natural speech in real time using a multi-codebook approach designed to reduce latency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqenmfvz1twio3948rmin.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqenmfvz1twio3948rmin.png" alt="Image" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Plus variant uses Mixture of Experts, or MoE. With MoE, only a subset of model parameters activates per token. This keeps inference more efficient than a dense model of equivalent quality.&lt;/p&gt;

&lt;p&gt;For local deployment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;vLLM&lt;/code&gt; when possible for MoE-optimized serving&lt;/li&gt;
&lt;li&gt;Use HuggingFace Transformers if you need broader compatibility&lt;/li&gt;
&lt;li&gt;Expect higher latency with Transformers on MoE architectures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basic local deployment decision flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Need production local serving?
→ Start with vLLM

Need experimentation or custom model loading?
→ Try HuggingFace Transformers

Limited GPU memory?
→ Test Flash or Light before Plus
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing Qwen3.5-Omni APIs with Apidog
&lt;/h2&gt;

&lt;p&gt;If you evaluate Qwen3.5-Omni through an API, you will likely send multimodal request bodies containing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text prompts&lt;/li&gt;
&lt;li&gt;Image URLs&lt;/li&gt;
&lt;li&gt;Base64-encoded audio&lt;/li&gt;
&lt;li&gt;Video references&lt;/li&gt;
&lt;li&gt;Model variant settings&lt;/li&gt;
&lt;li&gt;Streaming options&lt;/li&gt;
&lt;li&gt;Voice cloning parameters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftux0bpj6cs1yvaff9wkz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftux0bpj6cs1yvaff9wkz.png" alt="Image" width="799" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This gets hard to debug with raw &lt;code&gt;curl&lt;/code&gt; commands.&lt;/p&gt;

&lt;p&gt;Apidog is useful for building, saving, and testing these request templates. You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store DashScope API keys as environment variables&lt;/li&gt;
&lt;li&gt;Create reusable request bodies for Plus, Flash, and Light&lt;/li&gt;
&lt;li&gt;Compare latency across variants&lt;/li&gt;
&lt;li&gt;Validate response structure&lt;/li&gt;
&lt;li&gt;Write automated tests for expected fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example API test checklist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] Request returns HTTP 200
[ ] Response includes text output
[ ] Response includes audio output when requested
[ ] Latency is within target range
[ ] Language detection matches input
[ ] Streaming response starts before full generation completes
[ ] Error responses are handled correctly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A typical multimodal request template might include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"qwen3.5-omni-flash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"messages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Summarize this video and extract action items."&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"video_url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"video_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/demo.mp4"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"output_modalities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"audio"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"auto"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the same saved request against Plus, Flash, and Light to compare output quality and latency under identical inputs.&lt;/p&gt;

&lt;p&gt;Download Apidog free to start testing multimodal API requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should evaluate Qwen3.5-Omni?
&lt;/h2&gt;

&lt;p&gt;Qwen3.5-Omni is worth testing if you are building any of the following.&lt;/p&gt;

&lt;h3&gt;
  
  
  Voice assistants
&lt;/h3&gt;

&lt;p&gt;Use it for real-time speech input and speech output with conversation memory and web retrieval.&lt;/p&gt;

&lt;p&gt;The semantic interruption and ARIA features address two common voice UX problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;False interruptions&lt;/li&gt;
&lt;li&gt;Mispronounced technical terms&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Video analysis tools
&lt;/h3&gt;

&lt;p&gt;Use it for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Meeting transcription&lt;/li&gt;
&lt;li&gt;Product demo analysis&lt;/li&gt;
&lt;li&gt;Tutorial generation&lt;/li&gt;
&lt;li&gt;Video summarization&lt;/li&gt;
&lt;li&gt;Screen-recording-to-code workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 256K context window means many recordings can fit in one request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multilingual customer products
&lt;/h3&gt;

&lt;p&gt;Use it when your app needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;113-language ASR&lt;/li&gt;
&lt;li&gt;36-language TTS&lt;/li&gt;
&lt;li&gt;Language switching&lt;/li&gt;
&lt;li&gt;One multimodal model instead of multiple vendors&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Accessibility tooling
&lt;/h3&gt;

&lt;p&gt;Potential workflows include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alt text generation&lt;/li&gt;
&lt;li&gt;Audio descriptions for video&lt;/li&gt;
&lt;li&gt;Real-time captions&lt;/li&gt;
&lt;li&gt;Multilingual caption generation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Developer productivity tools
&lt;/h3&gt;

&lt;p&gt;Audio-Visual Vibe Coding lets developers provide screen recordings as context.&lt;/p&gt;

&lt;p&gt;Example prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Watch this screen recording of a UI interaction.

Generate:
1. React component structure
2. Required state management
3. CSS layout
4. Edge cases
5. A minimal working implementation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Access options
&lt;/h2&gt;

&lt;p&gt;Qwen3.5-Omni is available through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alibaba Cloud DashScope API for production API access&lt;/li&gt;
&lt;li&gt;qwen.ai for web-based testing&lt;/li&gt;
&lt;li&gt;HuggingFace Hub for model weights and local deployment&lt;/li&gt;
&lt;li&gt;ModelScope, recommended for users in mainland China&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The API follows Alibaba Cloud’s standard authentication model. You need a DashScope API key.&lt;/p&gt;

&lt;p&gt;Check the DashScope documentation for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Endpoint details&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Streaming support&lt;/li&gt;
&lt;li&gt;Pricing by modality&lt;/li&gt;
&lt;li&gt;Rate limits&lt;/li&gt;
&lt;li&gt;Model availability&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What to test before production
&lt;/h2&gt;

&lt;p&gt;Benchmarks are useful, but your own workload matters more.&lt;/p&gt;

&lt;p&gt;Before adopting Qwen3.5-Omni, test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your users’ accents&lt;/li&gt;
&lt;li&gt;Your supported languages&lt;/li&gt;
&lt;li&gt;Domain-specific vocabulary&lt;/li&gt;
&lt;li&gt;Audio quality from real devices&lt;/li&gt;
&lt;li&gt;Long recordings&lt;/li&gt;
&lt;li&gt;Noisy environments&lt;/li&gt;
&lt;li&gt;Video formats and resolutions&lt;/li&gt;
&lt;li&gt;Latency under load&lt;/li&gt;
&lt;li&gt;Voice cloning quality&lt;/li&gt;
&lt;li&gt;Streaming behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Voice cloning is API-only for now&lt;/li&gt;
&lt;li&gt;The qwen.ai web interface does not expose voice cloning yet&lt;/li&gt;
&lt;li&gt;Local deployment requires significant GPU memory&lt;/li&gt;
&lt;li&gt;The Plus variant, a 30B MoE model, needs at least 40GB VRAM for comfortable inference&lt;/li&gt;
&lt;li&gt;Flash and Light are more accessible for smaller deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How is Qwen3.5-Omni different from Qwen2.5-Omni?
&lt;/h3&gt;

&lt;p&gt;Qwen2.5-Omni supported 7B and 3B dense model sizes with 19 languages for speech. Qwen3.5-Omni uses an MoE architecture, expands speech recognition to 113 languages, adds voice cloning, and introduces ARIA for better audio quality. Benchmark performance and context length also increased.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I run Qwen3.5-Omni locally?
&lt;/h3&gt;

&lt;p&gt;Yes. You can run it with HuggingFace Transformers or vLLM.&lt;/p&gt;

&lt;p&gt;For production local deployment, vLLM is the better option because it handles MoE routing more efficiently.&lt;/p&gt;

&lt;p&gt;The Plus variant needs 40GB+ VRAM. Flash and Light run on smaller GPUs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is there a free tier?
&lt;/h3&gt;

&lt;p&gt;The qwen.ai web interface is free to use. API access through DashScope is paid.&lt;/p&gt;

&lt;p&gt;Pricing depends on modality, such as audio tokens, video frames, and text tokens. Check the DashScope pricing documentation for current details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does it support real-time streaming?
&lt;/h3&gt;

&lt;p&gt;Yes. The Thinker-Talker architecture outputs audio in streaming chunks, so the first audio bytes can arrive before the full response is generated.&lt;/p&gt;

&lt;p&gt;This is important for live voice conversations.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between Plus, Flash, and Light?
&lt;/h3&gt;

&lt;p&gt;Plus is the highest-quality variant and is best when accuracy matters more than speed.&lt;/p&gt;

&lt;p&gt;Flash balances speed and quality and is the best starting point for most production APIs.&lt;/p&gt;

&lt;p&gt;Light is the fastest option and is intended for latency-sensitive applications such as mobile or edge scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use my own voice with the API?
&lt;/h3&gt;

&lt;p&gt;Yes. Voice cloning is available through the API.&lt;/p&gt;

&lt;p&gt;You provide an audio sample of the target voice, and the model uses it for speech output.&lt;/p&gt;

&lt;p&gt;This feature is not available through the web interface yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does it compare to ElevenLabs for voice generation?
&lt;/h3&gt;

&lt;p&gt;On Alibaba’s benchmarks across 20 languages, Qwen3.5-Omni Plus outperforms ElevenLabs on multilingual voice stability.&lt;/p&gt;

&lt;p&gt;ElevenLabs still has a longer product track record and more voice-specific customization options. If you only need voice generation, compare both. If you need one integrated multimodal model, Qwen3.5-Omni is the cleaner architecture to test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is it safe to send sensitive audio or video data through the API?
&lt;/h3&gt;

&lt;p&gt;Review Alibaba Cloud’s data processing agreement before sending sensitive data.&lt;/p&gt;

&lt;p&gt;As with any cloud API, assume data may be logged unless the agreement explicitly states otherwise.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Pretext.js: The 15KB Library That Makes Text Layout 500x Faster</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Tue, 23 Jun 2026 01:01:35 +0000</pubDate>
      <link>https://dev.to/preecha/pretextjs-the-15kb-library-that-makes-text-layout-500x-faster-5a4d</link>
      <guid>https://dev.to/preecha/pretextjs-the-15kb-library-that-makes-text-layout-500x-faster-5a4d</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Pretext.js is a zero-dependency TypeScript library that measures and positions multiline text with arithmetic instead of DOM layout reads. It avoids forced synchronous reflows, reports benchmarks up to ~500x faster than &lt;code&gt;getBoundingClientRect()&lt;/code&gt; for text measurement, and supports major writing systems. If you build virtual scrollers, chat UIs, or data grids, it targets one of the most expensive browser UI bottlenecks: measuring dynamic text.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Every time JavaScript calls &lt;code&gt;getBoundingClientRect()&lt;/code&gt; or reads layout properties like &lt;code&gt;offsetHeight&lt;/code&gt;, the browser may stop to flush pending styles, recalculate layout, and return the computed value. That forced synchronous reflow is expensive.&lt;/p&gt;

&lt;p&gt;Now apply that to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1,000 chat bubbles in a virtualized list&lt;/li&gt;
&lt;li&gt;10,000 rows in a data grid&lt;/li&gt;
&lt;li&gt;Streaming API responses that constantly append text&lt;/li&gt;
&lt;li&gt;Multilingual feeds with unpredictable line wrapping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is usually dropped frames, visible scroll jumps, and layout jank.&lt;/p&gt;

&lt;p&gt;Apidog teams building API-driven frontends know this pain well: streaming response data into dynamic UIs is hard when every layout measurement fights the rendering pipeline.&lt;/p&gt;

&lt;p&gt;Cheng Lou, the developer behind &lt;code&gt;react-motion&lt;/code&gt; and a core contributor to React and ReasonML at Meta, built Pretext.js to address this. The library shipped in March 2026, gained 14,000+ GitHub stars in days, and triggered a large Hacker News discussion.&lt;/p&gt;

&lt;p&gt;This guide focuses on how Pretext.js works, where it fits, how to integrate it, and when not to use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Pretext.js?
&lt;/h2&gt;

&lt;p&gt;Pretext.js is a pure JavaScript/TypeScript text layout engine. It measures and positions multiline text through arithmetic instead of DOM reads.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No &lt;code&gt;getBoundingClientRect()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;offsetHeight&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;No forced reflow during layout calculation&lt;/li&gt;
&lt;li&gt;No off-screen DOM measurement loop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj9jh5milb4qivpf313w9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj9jh5milb4qivpf313w9.png" alt="Image" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The core idea: instead of asking the browser, “How tall is this rendered text?”, Pretext.js computes the answer from font metrics and line-breaking rules.&lt;/p&gt;

&lt;p&gt;Basic usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;layout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@chenglou/pretext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Step 1: prepare text once&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, pretext.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;16px "Inter"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Step 2: compute layout at a target width&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lineCount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lineCount&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API has two main functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;prepare(text, font)&lt;/code&gt; measures and caches text segments.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;layout(handle, width, lineHeight)&lt;/code&gt; computes wrapping and height.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;prepare()&lt;/code&gt; touches the browser through Canvas text measurement. After that, &lt;code&gt;layout()&lt;/code&gt; is arithmetic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters for API-heavy applications
&lt;/h2&gt;

&lt;p&gt;If your app consumes streaming or frequently changing API data, you often need to know text height before rendering.&lt;/p&gt;

&lt;p&gt;Common examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI chat interfaces streaming tokens&lt;/li&gt;
&lt;li&gt;Real-time dashboards showing logs or events&lt;/li&gt;
&lt;li&gt;Collaborative editors&lt;/li&gt;
&lt;li&gt;Chat and comment feeds&lt;/li&gt;
&lt;li&gt;Data grids with variable-height cells&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without precomputed heights, virtual scrollers usually fall back to one of these options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Render first, measure later.&lt;/li&gt;
&lt;li&gt;Estimate height, then correct after render.&lt;/li&gt;
&lt;li&gt;Force fixed-height rows.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All three have tradeoffs. Pretext.js gives you a way to compute text height before creating DOM nodes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem Pretext.js solves
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Forced synchronous reflow
&lt;/h3&gt;

&lt;p&gt;This pattern is common and expensive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.text-block&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;el&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;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBoundingClientRect&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="c1"&gt;// use height for positioning...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each layout read can force the browser to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pause JavaScript&lt;/li&gt;
&lt;li&gt;Flush pending style changes&lt;/li&gt;
&lt;li&gt;Recalculate layout&lt;/li&gt;
&lt;li&gt;Return the computed geometry&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In loops, this becomes layout thrashing.&lt;/p&gt;

&lt;p&gt;For virtualized UI, that cost is especially painful because the whole point is to avoid rendering and measuring thousands of DOM nodes.&lt;/p&gt;

&lt;h3&gt;
  
  
  The virtual scrolling problem
&lt;/h3&gt;

&lt;p&gt;Virtual scrollers such as &lt;code&gt;react-window&lt;/code&gt; or &lt;code&gt;@tanstack/react-virtual&lt;/code&gt; need item heights to compute scroll offsets.&lt;/p&gt;

&lt;p&gt;Fixed-height rows are easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rowHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;48&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;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;rowHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Variable-height text is harder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;heights&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The challenge is getting &lt;code&gt;heights&lt;/code&gt; without rendering every row.&lt;/p&gt;

&lt;p&gt;Traditional options include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hidden off-screen render containers&lt;/li&gt;
&lt;li&gt;Post-render measurement&lt;/li&gt;
&lt;li&gt;Estimated heights&lt;/li&gt;
&lt;li&gt;Fixed-height constraints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pretext.js replaces those workarounds with a pre-render calculation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmark numbers
&lt;/h2&gt;

&lt;p&gt;Pretext.js published benchmark results comparing DOM measurement with &lt;code&gt;layout()&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;1,000 text blocks&lt;/th&gt;
&lt;th&gt;500 text blocks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DOM with &lt;code&gt;getBoundingClientRect()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;~94ms&lt;/td&gt;
&lt;td&gt;~47ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pretext.js &lt;code&gt;layout()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;~2ms&lt;/td&gt;
&lt;td&gt;~0.09ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed difference&lt;/td&gt;
&lt;td&gt;~47x faster&lt;/td&gt;
&lt;td&gt;~500x faster&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The improvement comes from avoiding layout reads. DOM measurement has browser rendering overhead; Pretext’s &lt;code&gt;layout()&lt;/code&gt; step is arithmetic over prepared segment widths.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Pretext.js works
&lt;/h2&gt;

&lt;p&gt;Pretext.js has three main phases.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Text segmentation
&lt;/h2&gt;

&lt;p&gt;When you call &lt;code&gt;prepare()&lt;/code&gt;, Pretext.js normalizes and segments the input text.&lt;/p&gt;

&lt;p&gt;It accounts for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Whitespace handling&lt;/li&gt;
&lt;li&gt;Unicode line breaking rules, including UAX #14&lt;/li&gt;
&lt;li&gt;Breakable units&lt;/li&gt;
&lt;li&gt;Multilingual text behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This matters because line wrapping is not the same across writing systems.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CJK text can break at character-level boundaries.&lt;/li&gt;
&lt;li&gt;Arabic and Hebrew require bidirectional text handling.&lt;/li&gt;
&lt;li&gt;Thai does not use spaces between words in the same way English does.&lt;/li&gt;
&lt;li&gt;Hindi/Devanagari can include conjunct consonants and ligatures.&lt;/li&gt;
&lt;li&gt;Emoji can span multiple code points.&lt;/li&gt;
&lt;li&gt;Soft hyphens introduce conditional break opportunities.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Canvas measurement
&lt;/h2&gt;

&lt;p&gt;After segmentation, Pretext.js measures segments with Canvas &lt;code&gt;measureText()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Example of the underlying browser primitive:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;OffscreenCanvas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&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;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2d&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Canvas context unavailable&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="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;font&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;16px "Inter"&lt;/span&gt;&lt;span class="dl"&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;metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;measureText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello&lt;/span&gt;&lt;span class="dl"&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;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Canvas text measurement does not trigger DOM layout reflow. Pretext.js caches measurements by segment and font combination, so repeated text/font pairs can reuse previous work.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Arithmetic layout
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;layout()&lt;/code&gt; takes the prepared handle, a target width, and a line height.&lt;/p&gt;

&lt;p&gt;Conceptually, it does this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;currentLineWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lineCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;for &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;segment&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;currentLineWidth&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;containerWidth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;lineCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;currentLineWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;currentLineWidth&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;segment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&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;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lineCount&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;lineHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The actual implementation handles Unicode and text layout details, but the performance win comes from the same principle: no DOM, no reflow, no render pass.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reuse prepared handles
&lt;/h2&gt;

&lt;p&gt;One useful pattern is preparing text once and laying it out at multiple widths.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;layout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@chenglou/pretext&lt;/span&gt;&lt;span class="dl"&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;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;longArticleText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;16px "Inter"&lt;/span&gt;&lt;span class="dl"&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;mobile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;375&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&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;tablet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;768&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&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;desktop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;mobileHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mobile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tabletHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;tablet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;desktopHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;desktop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&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;This is useful for responsive layouts where the same content needs to be measured against different container widths.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical implementation patterns
&lt;/h2&gt;

&lt;h2&gt;
  
  
  1. Variable-height virtual scrolling
&lt;/h2&gt;

&lt;p&gt;Use Pretext.js to precompute row heights before passing them into a virtualizer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;layout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@chenglou/pretext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;TextItem&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;computeHeights&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TextItem&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;containerWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;font&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;14px "Inter"&lt;/span&gt;&lt;span class="dl"&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;lineHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&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;verticalPadding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;item&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;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;font&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;containerWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lineHeight&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;verticalPadding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&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;heights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computeHeights&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chatMessages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This avoids:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rendering hidden rows&lt;/li&gt;
&lt;li&gt;Measuring DOM nodes&lt;/li&gt;
&lt;li&gt;Correcting estimated heights after paint&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. AI chat interfaces
&lt;/h2&gt;

&lt;p&gt;Streaming chat UIs update text many times while a response is being generated. If every update causes DOM measurement, the UI can stutter.&lt;/p&gt;

&lt;p&gt;With Pretext.js, update the item height from text data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;layout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@chenglou/pretext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;streamedText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&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;font&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;15px "SF Pro"&lt;/span&gt;&lt;span class="dl"&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;lineHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&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;bubbleWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;520&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;padding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token&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="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="nx"&gt;streamedText&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;token&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;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;streamedText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;font&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bubbleWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lineHeight&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;scroller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateItemHeight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messageId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;padding&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;For better performance, batch token updates instead of recalculating on every single character:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;pending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;scheduled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;token&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="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="nx"&gt;pending&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;scheduled&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;scheduled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;requestAnimationFrame&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="nx"&gt;streamedText&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;pending&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;pending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;scheduled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;streamedText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;font&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bubbleWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lineHeight&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;scroller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateItemHeight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messageId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&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;h2&gt;
  
  
  3. Data grids with text-heavy cells
&lt;/h2&gt;

&lt;p&gt;Data grids often need row heights before rendering visible rows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;layout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@chenglou/pretext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;GridRow&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;computeRowHeight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GridRow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;columnWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;font&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;13px system-ui&lt;/span&gt;&lt;span class="dl"&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;lineHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&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;verticalPadding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&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;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;font&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;columnWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lineHeight&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;verticalPadding&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;Use this when rows contain long descriptions, logs, comments, or other variable-length text.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Multilingual feeds
&lt;/h2&gt;

&lt;p&gt;Mixed-script feeds are difficult to virtualize because line-breaking behavior varies across languages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;layout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@chenglou/pretext&lt;/span&gt;&lt;span class="dl"&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;posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This library changed everything&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&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="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RTL text with correct bidirectional layout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ar&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="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CJK text gets proper character-level breaks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zh&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;font&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;16px system-ui&lt;/span&gt;&lt;span class="dl"&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;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&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;lineHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;for &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;post&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;posts&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;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&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;font&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lineCount&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lineHeight&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lineCount&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;The same API handles different writing systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing text-heavy API flows with Apidog
&lt;/h2&gt;

&lt;p&gt;When a UI depends on API-provided text, layout correctness also depends on response quality.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4iq5qg0nxweql6gz4ejw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4iq5qg0nxweql6gz4ejw.png" alt="Image" width="799" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use Apidog to test the API payloads that feed your text components. For example, you can create scenarios for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Short, medium, and long text responses&lt;/li&gt;
&lt;li&gt;Streaming chunks that simulate LLM output&lt;/li&gt;
&lt;li&gt;Multilingual payloads&lt;/li&gt;
&lt;li&gt;Emoji and Unicode edge cases&lt;/li&gt;
&lt;li&gt;Empty or missing text fields&lt;/li&gt;
&lt;li&gt;Unexpectedly large responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For AI chat products, this helps validate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chunked streaming behavior&lt;/li&gt;
&lt;li&gt;Response schema correctness&lt;/li&gt;
&lt;li&gt;Text field formats&lt;/li&gt;
&lt;li&gt;Edge cases that affect rendering&lt;/li&gt;
&lt;li&gt;Automated regression coverage for text layout bugs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fast measurement helps, but bad API data can still produce broken UI. Test both the rendering layer and the API responses that drive it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Known limitations
&lt;/h2&gt;

&lt;p&gt;Pretext.js is not a replacement for the browser layout engine in every case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rendering accuracy edge cases
&lt;/h2&gt;

&lt;p&gt;Because Pretext.js computes layout separately from DOM rendering, it can diverge from the browser in some cases.&lt;/p&gt;

&lt;p&gt;Potential causes include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unusual kerning pairs&lt;/li&gt;
&lt;li&gt;Mixed font sizes inside one block&lt;/li&gt;
&lt;li&gt;Subpixel rendering differences&lt;/li&gt;
&lt;li&gt;Browser-specific text shaping behavior&lt;/li&gt;
&lt;li&gt;Differences between Canvas measurement and DOM text rendering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For virtual scrolling, small differences may be acceptable. For pixel-perfect typography, DOM measurement remains the ground truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;prepare()&lt;/code&gt; still has a cost
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;layout()&lt;/code&gt; is fast, but &lt;code&gt;prepare()&lt;/code&gt; still uses Canvas measurement.&lt;/p&gt;

&lt;p&gt;Avoid calling &lt;code&gt;prepare()&lt;/code&gt; repeatedly for unchanged text. Cache handles by text and font:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;layout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@chenglou/pretext&lt;/span&gt;&lt;span class="dl"&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;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;prepare&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getPreparedText&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;font&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;font&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;::&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;prepare&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;font&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;measureTextHeight&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;font&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lineHeight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getPreparedText&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;font&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lineHeight&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;height&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;h2&gt;
  
  
  Limited CSS property support
&lt;/h2&gt;

&lt;p&gt;Pretext.js measures raw text with a font specification. It does not fully account for CSS properties such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;letter-spacing&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;word-spacing&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text-indent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;text-transform&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-feature-settings&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;font-variant&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your rendered text depends heavily on these properties, measured height may not match the DOM.&lt;/p&gt;

&lt;h2&gt;
  
  
  It does not render text
&lt;/h2&gt;

&lt;p&gt;Pretext.js computes text layout metrics. It does not display text.&lt;/p&gt;

&lt;p&gt;You still render with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DOM&lt;/li&gt;
&lt;li&gt;Canvas&lt;/li&gt;
&lt;li&gt;SVG&lt;/li&gt;
&lt;li&gt;WebGL&lt;/li&gt;
&lt;li&gt;Another rendering target&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Its value is in the measurement step before rendering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pretext.js vs. traditional approaches
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Pretext.js&lt;/th&gt;
&lt;th&gt;DOM measurement&lt;/th&gt;
&lt;th&gt;Estimated heights&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Speed for 1K items&lt;/td&gt;
&lt;td&gt;~2ms&lt;/td&gt;
&lt;td&gt;~94ms&lt;/td&gt;
&lt;td&gt;~0ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accuracy&lt;/td&gt;
&lt;td&gt;High, Canvas-based&lt;/td&gt;
&lt;td&gt;Ground truth&lt;/td&gt;
&lt;td&gt;Heuristic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DOM dependency&lt;/td&gt;
&lt;td&gt;None after &lt;code&gt;prepare()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Full&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reflow triggers&lt;/td&gt;
&lt;td&gt;Zero during &lt;code&gt;layout()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;One per measurement&lt;/td&gt;
&lt;td&gt;Zero&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multilingual support&lt;/td&gt;
&lt;td&gt;Unicode-aware&lt;/td&gt;
&lt;td&gt;Browser-native&lt;/td&gt;
&lt;td&gt;Usually poor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSS property support&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Full&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory overhead&lt;/td&gt;
&lt;td&gt;Cached segments&lt;/td&gt;
&lt;td&gt;DOM nodes&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Responsive layout&lt;/td&gt;
&lt;td&gt;One &lt;code&gt;prepare()&lt;/code&gt;, many &lt;code&gt;layout()&lt;/code&gt; calls&lt;/td&gt;
&lt;td&gt;Re-measure per width&lt;/td&gt;
&lt;td&gt;Re-estimate per width&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use DOM measurement when you need maximum fidelity. Use Pretext.js when you need fast pre-render measurement for many text blocks and can tolerate minor differences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @chenglou/pretext
&lt;span class="c"&gt;# or&lt;/span&gt;
pnpm add @chenglou/pretext
&lt;span class="c"&gt;# or&lt;/span&gt;
bun add @chenglou/pretext
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Basic usage
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;layout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@chenglou/pretext&lt;/span&gt;&lt;span class="dl"&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;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Pretext.js computes text layout without touching the DOM.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;16px "Inter"&lt;/span&gt;&lt;span class="dl"&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lineCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  React integration with TanStack Virtual
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;layout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@chenglou/pretext&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useVirtualizer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tanstack/react-virtual&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useMemo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;VirtualChat&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&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;parentRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HTMLDivElement&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&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;containerWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;600&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;font&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;14px "Inter"&lt;/span&gt;&lt;span class="dl"&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;lineHeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&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;verticalPadding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;24&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;heights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useMemo&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;message&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;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;font&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;containerWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lineHeight&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;verticalPadding&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;messages&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;virtualizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useVirtualizer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;getScrollElement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;parentRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;estimateSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;heights&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;parentRef&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;100vh&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
        &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;virtualizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTotalSize&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
          &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;relative&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="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;virtualizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getVirtualItems&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;virtualRow&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;
            &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;virtualRow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;absolute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;virtualRow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;containerWidth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;virtualRow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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;This computes item heights before messages are rendered by the virtual list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait for web fonts before measuring
&lt;/h2&gt;

&lt;p&gt;If your app uses web fonts, make sure they are loaded before calling &lt;code&gt;prepare()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;measureAfterFontsLoad&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="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fonts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ready&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;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;prepare&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;16px "Inter"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&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;If the font is not loaded, Canvas may measure with a fallback font and produce incorrect results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interactive playground
&lt;/h2&gt;

&lt;p&gt;The Pretext.js website includes an interactive playground at &lt;code&gt;pretextjs.dev/playground&lt;/code&gt;, where you can paste text, choose fonts, adjust container width, and inspect layout behavior before integrating it.&lt;/p&gt;

&lt;h2&gt;
  
  
  When not to use Pretext.js
&lt;/h2&gt;

&lt;p&gt;Avoid Pretext.js when the browser already solves your problem cheaply.&lt;/p&gt;

&lt;p&gt;Good reasons not to use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your page is static and not virtualized.&lt;/li&gt;
&lt;li&gt;You only have a small list of items.&lt;/li&gt;
&lt;li&gt;You need pixel-perfect print layout.&lt;/li&gt;
&lt;li&gt;Your text depends heavily on CSS text properties.&lt;/li&gt;
&lt;li&gt;You need server-side measurement without Canvas polyfills.&lt;/li&gt;
&lt;li&gt;DOM measurement cost is already negligible in your UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, measuring 50 static elements may be fast enough with the DOM. The extra dependency may not be worth it.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Is Pretext.js production-ready?
&lt;/h2&gt;

&lt;p&gt;The library shipped in March 2026 and gained 14,000+ GitHub stars within days. Its creator, Cheng Lou, runs Midjourney’s frontend, and the test suite covers many languages and edge cases.&lt;/p&gt;

&lt;p&gt;That said, it is still a new release. Pin your dependency version and test it with your actual fonts, content, browsers, and layout constraints.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does it work with React, Vue, and Svelte?
&lt;/h2&gt;

&lt;p&gt;Yes. Pretext.js is framework-agnostic.&lt;/p&gt;

&lt;p&gt;You can call &lt;code&gt;prepare()&lt;/code&gt; and &lt;code&gt;layout()&lt;/code&gt; from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React hooks&lt;/li&gt;
&lt;li&gt;Vue composables&lt;/li&gt;
&lt;li&gt;Svelte stores&lt;/li&gt;
&lt;li&gt;Plain JavaScript modules&lt;/li&gt;
&lt;li&gt;Worker-like architecture where browser APIs are available&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How does it handle web fonts?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;prepare()&lt;/code&gt; measures with the font available at call time. If the web font has not loaded, measurement may use a fallback font.&lt;/p&gt;

&lt;p&gt;Use the Font Loading API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fonts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then call &lt;code&gt;prepare()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can it be used for Canvas or SVG rendering?
&lt;/h2&gt;

&lt;p&gt;Yes. The computed layout data can inform rendering in DOM, Canvas, SVG, WebGL, or other targets.&lt;/p&gt;

&lt;p&gt;Pretext.js handles measurement and layout calculation, not rendering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does it support RTL languages?
&lt;/h2&gt;

&lt;p&gt;Yes. Pretext.js supports Arabic, Hebrew, and mixed-direction text with bidirectional handling.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the bundle size?
&lt;/h2&gt;

&lt;p&gt;The article reports a 15KB minified bundle with zero dependencies. It uses standard browser APIs such as Canvas &lt;code&gt;measureText()&lt;/code&gt; and &lt;code&gt;Intl.Segmenter&lt;/code&gt; where available.&lt;/p&gt;

&lt;h2&gt;
  
  
  How accurate is it compared to DOM measurement?
&lt;/h2&gt;

&lt;p&gt;For most text content, the article reports that Pretext.js matches DOM layout within roughly 1–2 pixels. Accuracy depends on fonts, browser behavior, and CSS properties.&lt;/p&gt;

&lt;p&gt;If you use unsupported CSS properties like &lt;code&gt;letter-spacing&lt;/code&gt; or &lt;code&gt;word-spacing&lt;/code&gt;, expect larger differences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can it measure styled text?
&lt;/h2&gt;

&lt;p&gt;Each &lt;code&gt;prepare()&lt;/code&gt; call accepts a single font specification. For mixed styles, such as bold words inside regular text, you need to split the text into style runs and measure them separately.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Pretext.js gives developers a practical way to measure multiline text without forcing DOM reflow. For virtual scrollers, chat interfaces, data grids, and streaming text UIs, that can remove a major source of layout jank.&lt;/p&gt;

&lt;p&gt;The tradeoff is fidelity. It does not fully support every CSS text property, can differ from DOM rendering in edge cases, and still requires Canvas measurement during &lt;code&gt;prepare()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Use it when you need fast pre-render text heights across many dynamic items. Keep DOM measurement when you need browser-perfect layout accuracy.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Use ByteDance DeerFlow 2.0 in 2026: Setup, Features, Security, and API Workflow Fit</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Mon, 22 Jun 2026 13:02:30 +0000</pubDate>
      <link>https://dev.to/preecha/how-to-use-bytedance-deerflow-20-in-2026-setup-features-security-and-api-workflow-fit-pl8</link>
      <guid>https://dev.to/preecha/how-to-use-bytedance-deerflow-20-in-2026-setup-features-security-and-api-workflow-fit-pl8</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR / Quick Answer
&lt;/h2&gt;

&lt;p&gt;DeerFlow 2.0 is an open-source super-agent harness from ByteDance for long-horizon tasks, multi-agent delegation, sandboxed execution, and skills-based extensibility. It is not just a coding copilot; it is an execution runtime for complex workflows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;If your team needs end-to-end autonomous task handling, DeerFlow is a strong fit. If your team also ships APIs, pair it with Apidog as your API quality layer for contract design, test governance, mock environments, and documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why DeerFlow Is Getting Attention
&lt;/h2&gt;

&lt;p&gt;Most AI development tools help with one task at a time: generating code, answering questions, summarizing research, or automating a small workflow.&lt;/p&gt;

&lt;p&gt;DeerFlow targets a broader use case: orchestrating work across multiple steps.&lt;/p&gt;

&lt;p&gt;According to the project description, DeerFlow combines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sub-agents&lt;/li&gt;
&lt;li&gt;memory&lt;/li&gt;
&lt;li&gt;sandbox execution&lt;/li&gt;
&lt;li&gt;tools and skills&lt;/li&gt;
&lt;li&gt;message gateway channels&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That matters because real engineering work rarely fits into one prompt. A useful agent runtime needs to decompose work, inspect files, execute commands, produce artifacts, and iterate based on results.&lt;/p&gt;

&lt;h2&gt;
  
  
  What DeerFlow 2.0 Actually Changed
&lt;/h2&gt;

&lt;p&gt;DeerFlow 2.0 is a full rewrite. The maintainers state that it shares no code with the 1.x branch.&lt;/p&gt;

&lt;p&gt;Practical takeaway:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;main&lt;/code&gt; if you want the current DeerFlow 2.0 super-agent harness architecture.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;main-1.x&lt;/code&gt; only if you intentionally need legacy behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are evaluating DeerFlow today, treat 2.0 as the baseline.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9uycr5qdeejia4cvyx6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9uycr5qdeejia4cvyx6.png" alt="Image" width="799" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Capability Breakdown
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Skills and Tools
&lt;/h3&gt;

&lt;p&gt;DeerFlow loads skills progressively instead of injecting every capability into the model context at once.&lt;/p&gt;

&lt;p&gt;That helps with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;long sessions&lt;/li&gt;
&lt;li&gt;token-sensitive models&lt;/li&gt;
&lt;li&gt;workflows where the agent only needs certain capabilities at specific stages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;built-in tools&lt;/li&gt;
&lt;li&gt;custom tools&lt;/li&gt;
&lt;li&gt;MCP server integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your team already uses MCP-based integrations, DeerFlow can fit into that tool ecosystem more easily.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Sub-Agents
&lt;/h3&gt;

&lt;p&gt;The lead agent can delegate work to sub-agents with isolated contexts.&lt;/p&gt;

&lt;p&gt;Use this for workflows like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repository analysis + test planning + refactor proposal&lt;/li&gt;
&lt;li&gt;research + implementation + documentation handoff&lt;/li&gt;
&lt;li&gt;content generation + validation + publishing preparation&lt;/li&gt;
&lt;li&gt;API implementation + test generation + review&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The practical benefit is separation of responsibilities. Instead of forcing one agent context to handle everything, you can split the task into smaller execution stages.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Sandbox and Filesystem
&lt;/h3&gt;

&lt;p&gt;DeerFlow is designed to run execution inside a sandboxed environment with auditable file operations and command execution.&lt;/p&gt;

&lt;p&gt;This is a major difference between a chatbot and an agent runtime.&lt;/p&gt;

&lt;p&gt;A chatbot can suggest commands. An execution runtime can work through a task, create files, run commands, inspect outputs, and revise its approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Context Engineering and Summarization
&lt;/h3&gt;

&lt;p&gt;DeerFlow emphasizes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;context compression&lt;/li&gt;
&lt;li&gt;isolated sub-agent context&lt;/li&gt;
&lt;li&gt;summarization across long workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This helps reduce context bloat and keeps long-running tasks more stable.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Long-Term Memory
&lt;/h3&gt;

&lt;p&gt;DeerFlow supports memory that persists across sessions and is stored locally under user control.&lt;/p&gt;

&lt;p&gt;The project also documents improvements around duplicate-memory handling, which helps avoid repeated fact accumulation over time.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Channel Connectivity
&lt;/h3&gt;

&lt;p&gt;DeerFlow supports task intake from messaging channels such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Telegram&lt;/li&gt;
&lt;li&gt;Slack&lt;/li&gt;
&lt;li&gt;Feishu/Lark&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Channel configuration is handled in &lt;code&gt;config.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This makes DeerFlow useful for team workflows where the agent is not only accessed through a terminal or local UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Tutorial: Fastest Safe Path
&lt;/h2&gt;

&lt;p&gt;The official installation docs prioritize Docker when available. That is the safest default for most teams.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Clone the repository and initialize config
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/bytedance/deer-flow.git
&lt;span class="nb"&gt;cd &lt;/span&gt;deer-flow
make config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Configure model providers
&lt;/h3&gt;

&lt;p&gt;Edit &lt;code&gt;config.yaml&lt;/code&gt; and define at least one model.&lt;/p&gt;

&lt;p&gt;DeerFlow supports OpenAI-compatible APIs and CLI-backed providers.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;models&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gpt-5-responses&lt;/span&gt;
    &lt;span class="na"&gt;display_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GPT-5 (Responses API)&lt;/span&gt;
    &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;langchain_openai:ChatOpenAI&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gpt-5&lt;/span&gt;
    &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$OPENAI_API_KEY&lt;/span&gt;
    &lt;span class="na"&gt;use_responses_api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;output_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;responses/v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Set environment variables
&lt;/h3&gt;

&lt;p&gt;Set the values referenced by your model configuration.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-key
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TAVILY_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your-key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Start with Docker
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make docker-init
make docker-start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Default access URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:2026
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Use local mode only if needed
&lt;/h3&gt;

&lt;p&gt;If you are not using Docker, run the local setup checks and development server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make check
make &lt;span class="nb"&gt;install
&lt;/span&gt;make dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Security: The Part Most Teams Skip
&lt;/h2&gt;

&lt;p&gt;DeerFlow's own docs include a strong warning: high-privilege capabilities such as command execution, file operations, and business logic invocation can be risky when exposed without controls.&lt;/p&gt;

&lt;p&gt;Do not treat DeerFlow like a normal public web app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Safe baseline
&lt;/h3&gt;

&lt;p&gt;Start with these controls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep deployment local or trusted by default.&lt;/li&gt;
&lt;li&gt;If cross-network access is required, add IP allowlists.&lt;/li&gt;
&lt;li&gt;Put a reverse proxy with strong authentication in front.&lt;/li&gt;
&lt;li&gt;Isolate network segments where possible.&lt;/li&gt;
&lt;li&gt;Keep DeerFlow updated.&lt;/li&gt;
&lt;li&gt;Review which tools and commands are available to the agent.&lt;/li&gt;
&lt;li&gt;Do not enable messaging channels before you have access controls and runbooks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Common mistake
&lt;/h3&gt;

&lt;p&gt;The dangerous pattern is exposing DeerFlow publicly without strict authentication, network restrictions, and permission boundaries.&lt;/p&gt;

&lt;p&gt;Avoid that. Keep the default posture local-first and trusted-network-first.&lt;/p&gt;

&lt;h2&gt;
  
  
  DeerFlow vs Typical Coding Agent
&lt;/h2&gt;

&lt;p&gt;A better question than "Should DeerFlow replace my coding agent?" is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which tool should own which part of the workflow?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workflow need&lt;/th&gt;
&lt;th&gt;Typical coding agent&lt;/th&gt;
&lt;th&gt;DeerFlow 2.0&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;IDE-centric coding loop&lt;/td&gt;
&lt;td&gt;Strong&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-agent task decomposition&lt;/td&gt;
&lt;td&gt;Limited to moderate&lt;/td&gt;
&lt;td&gt;Strong&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Channel-driven operations&lt;/td&gt;
&lt;td&gt;Usually limited&lt;/td&gt;
&lt;td&gt;Strong&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime orchestration&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Strong&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Local trusted deployment focus&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;td&gt;Explicitly documented&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If your work is mostly PR coding loops, a coding agent may be enough.&lt;/p&gt;

&lt;p&gt;If your work spans orchestration, channels, research, artifact pipelines, and multi-step automation, DeerFlow is more aligned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Apidog Fits in a DeerFlow Stack
&lt;/h2&gt;

&lt;p&gt;A common mistake is expecting one agent framework to handle the entire software delivery lifecycle.&lt;/p&gt;

&lt;p&gt;DeerFlow can orchestrate and execute, but API lifecycle quality still needs a dedicated system.&lt;/p&gt;

&lt;h3&gt;
  
  
  What DeerFlow does well for API teams
&lt;/h3&gt;

&lt;p&gt;Use DeerFlow for execution-heavy work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scaffolding services and scripts&lt;/li&gt;
&lt;li&gt;running iterative implementation loops&lt;/li&gt;
&lt;li&gt;coordinating multi-step engineering automation&lt;/li&gt;
&lt;li&gt;delegating subtasks to specialized agents&lt;/li&gt;
&lt;li&gt;producing draft artifacts for review&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What API teams still need beyond DeerFlow
&lt;/h3&gt;

&lt;p&gt;API teams still need a reliable place for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;contract-first API design and review&lt;/li&gt;
&lt;li&gt;endpoint-level regression test suites&lt;/li&gt;
&lt;li&gt;reusable mock environments&lt;/li&gt;
&lt;li&gt;API debugging workflows&lt;/li&gt;
&lt;li&gt;publishable API documentation&lt;/li&gt;
&lt;li&gt;governance around schema and behavior changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is where Apidog fits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical architecture
&lt;/h3&gt;

&lt;p&gt;Use a split-responsibility model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DeerFlow automates engineering execution.&lt;/li&gt;
&lt;li&gt;Apidog defines and governs API behavior.&lt;/li&gt;
&lt;li&gt;DeerFlow can generate implementation and test candidates.&lt;/li&gt;
&lt;li&gt;Apidog remains the source of truth for contracts, mocks, tests, and documentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives you speed without losing control over API correctness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Adoption Blueprint: Week 1 to Week 4
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Week 1: Local pilot
&lt;/h3&gt;

&lt;p&gt;Start small.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run DeerFlow locally with Docker.&lt;/li&gt;
&lt;li&gt;Configure one model provider.&lt;/li&gt;
&lt;li&gt;Choose one internal workflow.&lt;/li&gt;
&lt;li&gt;Run it end to end.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example pilot workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Implement a new internal API endpoint from an existing contract,
generate a docs stub,
and produce test candidates.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not expose the service outside your local or trusted environment yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Week 2: Add task decomposition
&lt;/h3&gt;

&lt;p&gt;Introduce sub-agent stages.&lt;/p&gt;

&lt;p&gt;Example split:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Stage 1: Analyze the repository.
Stage 2: Identify implementation files.
Stage 3: Generate code changes.
Stage 4: Draft tests.
Stage 5: Summarize risks and review notes.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Track:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;where the agent gets stuck&lt;/li&gt;
&lt;li&gt;which prompts are too broad&lt;/li&gt;
&lt;li&gt;which tools are unnecessary&lt;/li&gt;
&lt;li&gt;which permissions need tightening&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Week 3: Add API governance guardrails
&lt;/h3&gt;

&lt;p&gt;Use Apidog to define and validate API behavior.&lt;/p&gt;

&lt;p&gt;Add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAPI contracts&lt;/li&gt;
&lt;li&gt;endpoint test collections&lt;/li&gt;
&lt;li&gt;mock responses&lt;/li&gt;
&lt;li&gt;documentation updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then make API tests the gate for DeerFlow-generated changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Week 4: Controlled scaling
&lt;/h3&gt;

&lt;p&gt;Only expand access after the local workflow is stable.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add messaging channels only if operations need them.&lt;/li&gt;
&lt;li&gt;Keep strict network and authentication boundaries.&lt;/li&gt;
&lt;li&gt;Document runbooks for approval, retry, rollback, and incident response.&lt;/li&gt;
&lt;li&gt;Define which agent actions require human review.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Strengths and Tradeoffs
&lt;/h2&gt;

&lt;h3&gt;
  
  
  DeerFlow strengths
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;long-horizon orchestration model&lt;/li&gt;
&lt;li&gt;sub-agent task decomposition&lt;/li&gt;
&lt;li&gt;sandbox and filesystem execution model&lt;/li&gt;
&lt;li&gt;skills-based extensibility&lt;/li&gt;
&lt;li&gt;MCP integration support&lt;/li&gt;
&lt;li&gt;active open-source momentum&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DeerFlow tradeoffs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;more operational complexity than simple coding assistants&lt;/li&gt;
&lt;li&gt;higher security responsibility outside local environments&lt;/li&gt;
&lt;li&gt;requires disciplined configuration&lt;/li&gt;
&lt;li&gt;needs governance for production-grade usage&lt;/li&gt;
&lt;li&gt;can produce risky outcomes if granted broad command or file permissions without controls&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hands-On Workflow: DeerFlow + Apidog for an API Delivery Loop
&lt;/h2&gt;

&lt;p&gt;Here is a practical workflow for teams shipping REST APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario
&lt;/h3&gt;

&lt;p&gt;You need to ship a new internal REST API endpoint with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;strict request and response contracts&lt;/li&gt;
&lt;li&gt;automated regression tests&lt;/li&gt;
&lt;li&gt;deploy-safe change checks&lt;/li&gt;
&lt;li&gt;fast iteration from idea to implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step A: Define the API contract in Apidog first
&lt;/h3&gt;

&lt;p&gt;Start with the contract before asking the agent to implement anything.&lt;/p&gt;

&lt;p&gt;Define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;endpoint path&lt;/li&gt;
&lt;li&gt;HTTP method&lt;/li&gt;
&lt;li&gt;request schema&lt;/li&gt;
&lt;li&gt;response schema&lt;/li&gt;
&lt;li&gt;error objects&lt;/li&gt;
&lt;li&gt;status codes&lt;/li&gt;
&lt;li&gt;authentication requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example contract checklist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /internal/users/search

Request:
- query: string
- limit: number
- cursor: string | null

Response:
- items: User[]
- nextCursor: string | null

Errors:
- 400 invalid_request
- 401 unauthorized
- 500 internal_error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This becomes the source of truth for the implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step B: Ask DeerFlow to generate implementation candidates
&lt;/h3&gt;

&lt;p&gt;Use DeerFlow for the execution-heavy parts.&lt;/p&gt;

&lt;p&gt;Good tasks for DeerFlow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scaffold route handlers&lt;/li&gt;
&lt;li&gt;implement service layer logic&lt;/li&gt;
&lt;li&gt;draft migration scripts&lt;/li&gt;
&lt;li&gt;generate unit test templates&lt;/li&gt;
&lt;li&gt;generate integration test templates&lt;/li&gt;
&lt;li&gt;inspect existing code patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Give DeerFlow specific contract constraints.&lt;/p&gt;

&lt;p&gt;Instead of this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build the user search endpoint.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Implement POST /internal/users/search according to the provided OpenAPI contract.

Constraints:
- Do not change the response shape.
- Preserve existing auth middleware.
- Add negative-path tests for invalid query and missing auth.
- Follow existing repository patterns for route registration.
- Summarize all files changed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step C: Run contract and regression tests in Apidog
&lt;/h3&gt;

&lt;p&gt;Validate the generated implementation against your Apidog test suite.&lt;/p&gt;

&lt;p&gt;Check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;contract conformance&lt;/li&gt;
&lt;li&gt;required fields&lt;/li&gt;
&lt;li&gt;optional fields&lt;/li&gt;
&lt;li&gt;error responses&lt;/li&gt;
&lt;li&gt;auth behavior&lt;/li&gt;
&lt;li&gt;backward compatibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If tests fail, send the concrete failure output back to DeerFlow.&lt;/p&gt;

&lt;p&gt;Example feedback prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The Apidog contract test failed.

Failure:
Expected response field `nextCursor` to be nullable string.
Actual response omitted `nextCursor` when there are no more results.

Update the implementation to always return `nextCursor: null` when no cursor exists.
Do not change the API contract.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps the agent focused on targeted fixes instead of broad rewrites.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step D: Keep governance boundaries clear
&lt;/h3&gt;

&lt;p&gt;Use this rule:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DeerFlow owns execution velocity.&lt;/li&gt;
&lt;li&gt;Apidog owns API correctness and collaboration governance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That boundary prevents agent drift, where generated implementation starts diverging from the intended API behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration Patterns That Work Well
&lt;/h2&gt;

&lt;p&gt;Teams usually succeed faster when they define explicit operating profiles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Profile 1: Local trusted development
&lt;/h3&gt;

&lt;p&gt;Best for early adoption.&lt;/p&gt;

&lt;p&gt;Use this when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one developer is testing DeerFlow&lt;/li&gt;
&lt;li&gt;workflows are experimental&lt;/li&gt;
&lt;li&gt;security boundaries are not fully documented yet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recommended setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run DeerFlow on loopback only&lt;/li&gt;
&lt;li&gt;keep sandbox local or Docker-based&lt;/li&gt;
&lt;li&gt;disable external channel ingress&lt;/li&gt;
&lt;li&gt;limit tool permissions&lt;/li&gt;
&lt;li&gt;avoid storing unnecessary secrets in the environment&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Profile 2: Internal team environment
&lt;/h3&gt;

&lt;p&gt;Use this for cross-device access inside a company network.&lt;/p&gt;

&lt;p&gt;Recommended setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;place DeerFlow behind an authenticated reverse proxy&lt;/li&gt;
&lt;li&gt;apply IP allowlists&lt;/li&gt;
&lt;li&gt;enforce audit logging for tool actions&lt;/li&gt;
&lt;li&gt;document allowed workflows&lt;/li&gt;
&lt;li&gt;restrict high-risk commands&lt;/li&gt;
&lt;li&gt;review channel integrations before enabling them&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Profile 3: Controlled automation cell
&lt;/h3&gt;

&lt;p&gt;Use this for higher-volume automation.&lt;/p&gt;

&lt;p&gt;Recommended setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dedicate a network segment&lt;/li&gt;
&lt;li&gt;use strict capability limits per agent role&lt;/li&gt;
&lt;li&gt;rotate provider credentials&lt;/li&gt;
&lt;li&gt;monitor provider usage&lt;/li&gt;
&lt;li&gt;log command execution&lt;/li&gt;
&lt;li&gt;define approval points for destructive actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These patterns align with DeerFlow's security recommendations and reduce operational risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Failure Modes and Fixes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Failure mode 1: One giant prompt
&lt;/h3&gt;

&lt;p&gt;Teams try to solve an entire workflow in one lead-agent pass.&lt;/p&gt;

&lt;p&gt;Result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;context instability&lt;/li&gt;
&lt;li&gt;unclear intermediate state&lt;/li&gt;
&lt;li&gt;poor debugging&lt;/li&gt;
&lt;li&gt;broad, unfocused changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;split work into sub-agent stages&lt;/li&gt;
&lt;li&gt;define completion criteria per stage&lt;/li&gt;
&lt;li&gt;write intermediate results to files&lt;/li&gt;
&lt;li&gt;summarize outputs before moving to the next stage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Analyze repo structure.
2. Identify files to modify.
3. Draft implementation plan.
4. Apply code changes.
5. Generate tests.
6. Run checks.
7. Summarize results.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Failure mode 2: Unclear model routing
&lt;/h3&gt;

&lt;p&gt;Multi-provider setups become hard to debug when every task can hit any model.&lt;/p&gt;

&lt;p&gt;Fix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;define task-to-model mapping in &lt;code&gt;config.yaml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;reserve stronger reasoning models for planning and decomposition&lt;/li&gt;
&lt;li&gt;use faster models for deterministic transform tasks&lt;/li&gt;
&lt;li&gt;document which provider handles which workflow type&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example routing policy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Planning: high-reasoning model
Code transformation: faster implementation model
Summarization: low-cost model
Validation review: high-reasoning model
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Failure mode 3: Security added too late
&lt;/h3&gt;

&lt;p&gt;Teams expose services to broader networks before authentication and network policies are ready.&lt;/p&gt;

&lt;p&gt;Fix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep local-first as the default&lt;/li&gt;
&lt;li&gt;add reverse proxy authentication before external exposure&lt;/li&gt;
&lt;li&gt;apply IP allowlists&lt;/li&gt;
&lt;li&gt;review command and file permissions&lt;/li&gt;
&lt;li&gt;delay channel integrations until access controls are ready&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Failure mode 4: No API quality gate
&lt;/h3&gt;

&lt;p&gt;Agent-generated changes may pass code review but still break integration contracts.&lt;/p&gt;

&lt;p&gt;Fix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;enforce Apidog contract tests in CI&lt;/li&gt;
&lt;li&gt;require a green API test suite before merge&lt;/li&gt;
&lt;li&gt;keep docs and mocks synchronized with contract updates&lt;/li&gt;
&lt;li&gt;send concrete test failures back to DeerFlow for targeted fixes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What to Measure After Adoption
&lt;/h2&gt;

&lt;p&gt;To decide whether DeerFlow is delivering real value, track operational metrics.&lt;/p&gt;

&lt;p&gt;Measure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cycle time from task intake to validated output&lt;/li&gt;
&lt;li&gt;defect rate on agent-assisted changes&lt;/li&gt;
&lt;li&gt;rework ratio after API contract validation&lt;/li&gt;
&lt;li&gt;number of failed automation runs&lt;/li&gt;
&lt;li&gt;number of incidents tied to permissions or sandbox configuration&lt;/li&gt;
&lt;li&gt;percentage of workflows that require manual recovery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then compare against your pre-DeerFlow baseline.&lt;/p&gt;

&lt;p&gt;Use the results to tune your setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If velocity improves but governance risk increases, tighten permissions and review gates.&lt;/li&gt;
&lt;li&gt;If governance is strong but velocity stalls, improve sub-agent decomposition and model routing.&lt;/li&gt;
&lt;li&gt;If output quality varies, add clearer completion criteria and validation steps.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is DeerFlow open source?
&lt;/h3&gt;

&lt;p&gt;Yes. DeerFlow is released under the MIT License.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is DeerFlow 2.0 the same as DeerFlow 1.x?
&lt;/h3&gt;

&lt;p&gt;No. The maintainers describe DeerFlow 2.0 as a ground-up rewrite. The 1.x line remains in a separate branch.&lt;/p&gt;

&lt;h3&gt;
  
  
  What runtime requirements should I expect?
&lt;/h3&gt;

&lt;p&gt;The project documents Python 3.12+ and Node.js 22+ in current materials. Docker is recommended for setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can DeerFlow be used only through terminal or UI?
&lt;/h3&gt;

&lt;p&gt;No. It also supports messaging-channel integrations and an embedded Python client path.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can DeerFlow replace Apidog for API teams?
&lt;/h3&gt;

&lt;p&gt;No. DeerFlow can automate implementation workflows, but it is not a replacement for API lifecycle governance.&lt;/p&gt;

&lt;p&gt;Apidog is the better layer for schema-first API design, testing, mocks, and documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Verdict
&lt;/h2&gt;

&lt;p&gt;DeerFlow 2.0 is a capable open-source agent harness for teams that need more than chatbot-style assistance.&lt;/p&gt;

&lt;p&gt;The best production posture is pragmatic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use DeerFlow for orchestration and execution&lt;/li&gt;
&lt;li&gt;use Apidog for API quality governance&lt;/li&gt;
&lt;li&gt;keep security boundaries strict from day one&lt;/li&gt;
&lt;li&gt;validate generated API changes against contracts before merge&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That architecture gives you both velocity and reliability.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Best API Catalog Tools: Top Solutions for 2026</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Mon, 22 Jun 2026 01:01:18 +0000</pubDate>
      <link>https://dev.to/preecha/best-api-catalog-tools-top-solutions-for-2026-4g8n</link>
      <guid>https://dev.to/preecha/best-api-catalog-tools-top-solutions-for-2026-4g8n</guid>
      <description>&lt;p&gt;As API estates grow across microservices, teams, and cloud platforms, an API catalog becomes the system of record developers use to find, understand, reuse, and govern APIs. This guide explains what API catalog tools do, which features matter in 2026, and how to evaluate options such as Apidog, DigitalAPI, RapidAPI Enterprise Hub, Collibra, Alation, Atlan, and MuleSoft API Catalog.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are API Catalog Tools?
&lt;/h2&gt;

&lt;p&gt;API catalog tools centralize API information in one searchable place. A good catalog typically stores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API documentation&lt;/li&gt;
&lt;li&gt;Ownership and team metadata&lt;/li&gt;
&lt;li&gt;API type and protocol&lt;/li&gt;
&lt;li&gt;Version information&lt;/li&gt;
&lt;li&gt;Lifecycle status&lt;/li&gt;
&lt;li&gt;Security and governance details&lt;/li&gt;
&lt;li&gt;Links to specs, gateways, repositories, or developer portals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In practice, an API catalog acts as the API source of truth for developers, architects, platform teams, and business stakeholders.&lt;/p&gt;

&lt;p&gt;Without a catalog, organizations often run into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Duplicate APIs built by different teams&lt;/li&gt;
&lt;li&gt;Inconsistent API standards&lt;/li&gt;
&lt;li&gt;Undocumented or "shadow" APIs&lt;/li&gt;
&lt;li&gt;Slow onboarding for new developers&lt;/li&gt;
&lt;li&gt;Weak auditability for compliance programs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A catalog helps teams answer practical questions quickly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does an API for this use case already exist?&lt;/li&gt;
&lt;li&gt;Who owns this API?&lt;/li&gt;
&lt;li&gt;Is this version still supported?&lt;/li&gt;
&lt;li&gt;Where is the OpenAPI spec?&lt;/li&gt;
&lt;li&gt;Can this API be reused safely?&lt;/li&gt;
&lt;li&gt;Is this endpoint compliant with internal policies?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why API Catalog Tools Matter in 2026
&lt;/h2&gt;

&lt;p&gt;Microservices, event-driven systems, and multi-cloud architectures have increased the number of APIs most teams need to manage. That flexibility is useful, but it also creates operational problems.&lt;/p&gt;

&lt;p&gt;Common API catalog use cases include:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Challenge&lt;/th&gt;
&lt;th&gt;How an API catalog helps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;API sprawl&lt;/td&gt;
&lt;td&gt;Creates a searchable inventory across teams, gateways, and environments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redundant development&lt;/td&gt;
&lt;td&gt;Helps developers find and reuse existing APIs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shadow APIs&lt;/td&gt;
&lt;td&gt;Improves visibility into undocumented or unmanaged endpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compliance&lt;/td&gt;
&lt;td&gt;Tracks ownership, lifecycle status, and policy metadata&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Onboarding delays&lt;/td&gt;
&lt;td&gt;Gives new developers one place to find API docs and usage details&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Version confusion&lt;/td&gt;
&lt;td&gt;Shows current, deprecated, and legacy API versions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For teams managing hundreds or thousands of APIs, a catalog is no longer just documentation. It becomes part of API governance, platform engineering, and developer experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features to Look For in an API Catalog Tool
&lt;/h2&gt;

&lt;p&gt;Use the following checklist when evaluating API catalog tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Unified API Discovery and Search
&lt;/h3&gt;

&lt;p&gt;A useful catalog should let developers search across different API types and metadata fields.&lt;/p&gt;

&lt;p&gt;Look for support for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;REST APIs&lt;/li&gt;
&lt;li&gt;SOAP APIs&lt;/li&gt;
&lt;li&gt;GraphQL APIs&lt;/li&gt;
&lt;li&gt;Event-driven APIs&lt;/li&gt;
&lt;li&gt;API version&lt;/li&gt;
&lt;li&gt;Owner or team&lt;/li&gt;
&lt;li&gt;Business domain&lt;/li&gt;
&lt;li&gt;Lifecycle status&lt;/li&gt;
&lt;li&gt;Tags or categories&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example search filters developers commonly need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;domain:payments status:production owner:platform
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type:graphql lifecycle:deprecated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tag:customer-data version:v2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Automated Documentation and Spec Import
&lt;/h3&gt;

&lt;p&gt;Manual API catalogs become stale quickly. Prioritize tools that can import or sync API definitions from existing sources.&lt;/p&gt;

&lt;p&gt;Useful import sources include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAPI / Swagger&lt;/li&gt;
&lt;li&gt;RAML&lt;/li&gt;
&lt;li&gt;Postman collections&lt;/li&gt;
&lt;li&gt;API gateways&lt;/li&gt;
&lt;li&gt;Source control repositories&lt;/li&gt;
&lt;li&gt;CI/CD pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A practical workflow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API spec updated -&amp;gt; CI pipeline runs -&amp;gt; catalog syncs latest spec -&amp;gt; docs update automatically
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This reduces the gap between implementation and documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Lifecycle and Governance Management
&lt;/h3&gt;

&lt;p&gt;API catalogs should make lifecycle status visible and enforceable.&lt;/p&gt;

&lt;p&gt;Typical lifecycle stages include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Design -&amp;gt; Development -&amp;gt; Testing -&amp;gt; Production -&amp;gt; Deprecated -&amp;gt; Retired
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Governance features to evaluate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Required ownership metadata&lt;/li&gt;
&lt;li&gt;Review and approval workflows&lt;/li&gt;
&lt;li&gt;Role-based access control&lt;/li&gt;
&lt;li&gt;Policy checks&lt;/li&gt;
&lt;li&gt;Deprecation tracking&lt;/li&gt;
&lt;li&gt;Audit history&lt;/li&gt;
&lt;li&gt;Compliance metadata&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a platform team may require every production API to include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments-platform&lt;/span&gt;
&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;security&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;oauth2&lt;/span&gt;
&lt;span class="na"&gt;documentation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;published&lt;/span&gt;
&lt;span class="na"&gt;deprecationDate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Versioning and Change Management
&lt;/h3&gt;

&lt;p&gt;A catalog should help developers understand which API version to use and what changed between releases.&lt;/p&gt;

&lt;p&gt;Look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Version history&lt;/li&gt;
&lt;li&gt;Changelogs&lt;/li&gt;
&lt;li&gt;Deprecation notices&lt;/li&gt;
&lt;li&gt;Breaking-change visibility&lt;/li&gt;
&lt;li&gt;Links to related specs or docs&lt;/li&gt;
&lt;li&gt;Consumer impact information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simple changelog entry might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## v2.1.0&lt;/span&gt;

&lt;span class="gu"&gt;### Added&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Added &lt;span class="sb"&gt;`customerTier`&lt;/span&gt; field to &lt;span class="sb"&gt;`GET /customers/{id}`&lt;/span&gt; response.

&lt;span class="gu"&gt;### Changed&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Updated pagination defaults for &lt;span class="sb"&gt;`GET /customers`&lt;/span&gt;.

&lt;span class="gu"&gt;### Deprecated&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Deprecated &lt;span class="sb"&gt;`legacyCustomerId`&lt;/span&gt;.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Collaboration and Usage Insight
&lt;/h3&gt;

&lt;p&gt;API catalogs are more useful when developers can contribute context.&lt;/p&gt;

&lt;p&gt;Helpful collaboration capabilities include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comments&lt;/li&gt;
&lt;li&gt;Documentation edits&lt;/li&gt;
&lt;li&gt;Ownership requests&lt;/li&gt;
&lt;li&gt;Feedback workflows&lt;/li&gt;
&lt;li&gt;Internal ratings or recommendations&lt;/li&gt;
&lt;li&gt;API usage analytics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Usage metrics can help platform teams identify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frequently reused APIs&lt;/li&gt;
&lt;li&gt;APIs with outdated docs&lt;/li&gt;
&lt;li&gt;APIs that should be deprecated&lt;/li&gt;
&lt;li&gt;APIs that need better onboarding examples&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Top API Catalog Tools for 2026
&lt;/h2&gt;

&lt;p&gt;Below are API catalog tools commonly used for cataloging, discoverability, governance, and integration across different organization types.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Apidog
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgk7i162ffld3wa5jei62.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgk7i162ffld3wa5jei62.png" alt="Image" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Apidog is an all-in-one API development platform for designing, cataloging, documenting, debugging, mocking, and testing APIs. It supports importing API specs from formats such as Swagger and Postman, generates interactive documentation, and helps teams keep API information updated as APIs evolve.&lt;/p&gt;

&lt;p&gt;Key capabilities include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Centralized API catalog with metadata and search&lt;/li&gt;
&lt;li&gt;Import from popular API formats&lt;/li&gt;
&lt;li&gt;Live online API documentation&lt;/li&gt;
&lt;li&gt;Integrated mocking, debugging, and testing&lt;/li&gt;
&lt;li&gt;UI designed for both technical and non-technical collaborators&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A practical Apidog workflow can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Import existing API specs.
2. Organize APIs by project, service, domain, or team.
3. Add ownership and lifecycle metadata.
4. Generate interactive documentation.
5. Share docs with internal developers or stakeholders.
6. Use built-in testing and mocking during development.
7. Update the catalog as APIs change.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apidog is a strong fit for teams that want API cataloging, documentation, testing, and collaboration in one workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. DigitalAPI
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0wuf3kg52pf6lrgle345.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0wuf3kg52pf6lrgle345.png" alt="Image" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;DigitalAPI is designed to unify distributed API estates into a single catalog. It focuses on multi-gateway aggregation, OpenAPI normalization, lifecycle management, policy management, and federated discovery.&lt;/p&gt;

&lt;p&gt;Best for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large enterprises&lt;/li&gt;
&lt;li&gt;Multi-cloud API environments&lt;/li&gt;
&lt;li&gt;Teams managing APIs across several gateways&lt;/li&gt;
&lt;li&gt;Organizations that need centralized API visibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implementation focus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Connect gateways -&amp;gt; Aggregate API inventory -&amp;gt; Normalize definitions -&amp;gt; Apply lifecycle and policy metadata -&amp;gt; Enable federated discovery
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. RapidAPI Enterprise Hub
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7kxujcpr3flhwfrmx98.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7kxujcpr3flhwfrmx98.png" alt="Image" width="799" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RapidAPI Enterprise Hub provides a private marketplace for internal and external APIs. It includes cataloging, analytics, access controls, search, and subscription management.&lt;/p&gt;

&lt;p&gt;Best for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enterprises sharing APIs across business units&lt;/li&gt;
&lt;li&gt;Organizations exposing APIs to partners&lt;/li&gt;
&lt;li&gt;Teams that need marketplace-style API discovery&lt;/li&gt;
&lt;li&gt;API programs with access approval workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A typical use case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Publish internal API -&amp;gt; Add docs and access rules -&amp;gt; Developers request access -&amp;gt; API owner approves subscription -&amp;gt; Usage is tracked
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Collibra
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq01gdupx5clvoksatae5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq01gdupx5clvoksatae5.png" alt="Image" width="800" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Collibra is primarily a data governance platform, but it also supports API cataloging capabilities with lineage tracking and policy enforcement.&lt;/p&gt;

&lt;p&gt;Best for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Regulated industries&lt;/li&gt;
&lt;li&gt;Data governance teams&lt;/li&gt;
&lt;li&gt;Organizations that need lineage from data assets to API consumers&lt;/li&gt;
&lt;li&gt;Compliance-focused API programs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use Collibra when API cataloging needs to connect closely with data governance, policy, and lineage workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Alation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdqmcb6weunbun4q8psnp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdqmcb6weunbun4q8psnp.png" alt="Image" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Alation provides API catalog capabilities as part of its broader data intelligence platform. Its strengths include discoverability, business metadata, and collaborative documentation.&lt;/p&gt;

&lt;p&gt;Best for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data-driven organizations&lt;/li&gt;
&lt;li&gt;Teams that want API metadata connected to broader data context&lt;/li&gt;
&lt;li&gt;Catalog programs emphasizing collaboration and business definitions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Atlan
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F28zwb7y720jq7rxcpzfx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F28zwb7y720jq7rxcpzfx.png" alt="Image" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Atlan is a modern data catalog platform with support for API discovery, metadata management, and lineage.&lt;/p&gt;

&lt;p&gt;Best for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data teams that need API visibility&lt;/li&gt;
&lt;li&gt;Enterprises connecting APIs with data assets&lt;/li&gt;
&lt;li&gt;Organizations focused on metadata and lineage across systems&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. MuleSoft API Catalog
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fmw4rkrhomia7ut9d5l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fmw4rkrhomia7ut9d5l.png" alt="Image" width="800" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MuleSoft Anypoint Exchange provides cataloging, versioning, and governance for APIs built and managed within the MuleSoft ecosystem.&lt;/p&gt;

&lt;p&gt;Best for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MuleSoft users&lt;/li&gt;
&lt;li&gt;Organizations standardized on Anypoint Platform&lt;/li&gt;
&lt;li&gt;Teams that need API cataloging inside an existing MuleSoft workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A typical MuleSoft-centered workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Design API -&amp;gt; Publish to Anypoint Exchange -&amp;gt; Manage versions -&amp;gt; Apply governance -&amp;gt; Enable reuse across MuleSoft projects
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Practical API Catalog Implementation Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Example 1: Improve Developer Onboarding with Apidog
&lt;/h3&gt;

&lt;p&gt;A fintech team can use Apidog to import existing APIs, organize them by business domain, and publish interactive documentation.&lt;/p&gt;

&lt;p&gt;Implementation steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Export or collect existing API specs.
2. Import specs into Apidog.
3. Group APIs by service, product, or domain.
4. Add owner and lifecycle metadata.
5. Publish interactive docs.
6. Share the catalog with new developers.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected outcome:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developers find APIs faster&lt;/li&gt;
&lt;li&gt;Teams avoid rebuilding existing endpoints&lt;/li&gt;
&lt;li&gt;Documentation stays closer to implementation&lt;/li&gt;
&lt;li&gt;API standards become easier to follow&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example 2: Enforce Governance Across Gateways with DigitalAPI
&lt;/h3&gt;

&lt;p&gt;A healthcare provider managing APIs across multiple gateways can use DigitalAPI to centralize discovery and policy visibility.&lt;/p&gt;

&lt;p&gt;Implementation steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Connect API gateways.
2. Aggregate APIs into one catalog.
3. Normalize API definitions.
4. Add lifecycle and ownership metadata.
5. Apply policy checks.
6. Track auditable records for compliance.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful when APIs must meet regulatory or internal governance requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 3: Support Multi-Cloud API Discovery with RapidAPI Enterprise Hub
&lt;/h3&gt;

&lt;p&gt;A retail organization running APIs across AWS, Azure, and on-premise systems can use RapidAPI Enterprise Hub to provide a unified API marketplace.&lt;/p&gt;

&lt;p&gt;Implementation steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Publish APIs from each environment.
2. Add searchable descriptions and tags.
3. Define access controls.
4. Enable developer subscriptions.
5. Track usage and adoption.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes it easier for internal teams and partners to discover and request access to APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example 4: Connect API and Data Governance with Collibra
&lt;/h3&gt;

&lt;p&gt;A data-driven enterprise can use Collibra to connect API metadata with data lineage and governance policies.&lt;/p&gt;

&lt;p&gt;Implementation steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Catalog APIs that expose governed data.
2. Link APIs to related data assets.
3. Add business definitions and policy metadata.
4. Track ownership and lineage.
5. Use the catalog for compliance reviews.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps teams understand how data moves from source systems to API consumers.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Apidog Fits into an API Catalog Workflow
&lt;/h2&gt;

&lt;p&gt;Apidog is useful when your API catalog needs to be more than a static registry. It combines cataloging with API design, documentation, debugging, mocking, and testing.&lt;/p&gt;

&lt;p&gt;A practical team workflow in Apidog could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Create or import an API definition.
2. Document endpoints, parameters, examples, and responses.
3. Generate interactive documentation.
4. Mock endpoints before backend implementation is complete.
5. Debug and test APIs during development.
6. Share the API with teammates for review.
7. Keep documentation updated as the API changes.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reasons teams may choose Apidog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Import existing APIs quickly&lt;/li&gt;
&lt;li&gt;Generate interactive API documentation&lt;/li&gt;
&lt;li&gt;Share APIs across teams&lt;/li&gt;
&lt;li&gt;Keep design, docs, tests, and mocks in one place&lt;/li&gt;
&lt;li&gt;Support collaboration between developers, QA, and product stakeholders&lt;/li&gt;
&lt;li&gt;Track changes and maintain a more reliable API catalog&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Choose the Right API Catalog Tool
&lt;/h2&gt;

&lt;p&gt;Use this evaluation checklist before choosing a tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Map Your API Sources
&lt;/h3&gt;

&lt;p&gt;List where APIs currently live:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- API gateways
- Git repositories
- OpenAPI files
- Postman collections
- Internal developer portals
- Cloud environments
- Service registries
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then check whether the catalog tool can import or sync from those sources.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Define Required Metadata
&lt;/h3&gt;

&lt;p&gt;Decide which fields every cataloged API must include.&lt;/p&gt;

&lt;p&gt;Example metadata model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Customer Profile API&lt;/span&gt;
&lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;customer-platform&lt;/span&gt;
&lt;span class="na"&gt;businessDomain&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;customer&lt;/span&gt;
&lt;span class="na"&gt;apiType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;REST&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v2&lt;/span&gt;
&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
&lt;span class="na"&gt;security&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OAuth2&lt;/span&gt;
&lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://example.com/repo&lt;/span&gt;
&lt;span class="na"&gt;documentationStatus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;published&lt;/span&gt;
&lt;span class="na"&gt;lastReviewed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-01-15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Check API Type Coverage
&lt;/h3&gt;

&lt;p&gt;Confirm support for the API styles your teams use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;REST&lt;/li&gt;
&lt;li&gt;SOAP&lt;/li&gt;
&lt;li&gt;GraphQL&lt;/li&gt;
&lt;li&gt;Async or event-driven APIs&lt;/li&gt;
&lt;li&gt;Internal APIs&lt;/li&gt;
&lt;li&gt;Partner APIs&lt;/li&gt;
&lt;li&gt;Public APIs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Review Governance and Access Control
&lt;/h3&gt;

&lt;p&gt;Evaluate whether the tool supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Role-based access&lt;/li&gt;
&lt;li&gt;Approval workflows&lt;/li&gt;
&lt;li&gt;Ownership tracking&lt;/li&gt;
&lt;li&gt;Lifecycle states&lt;/li&gt;
&lt;li&gt;Deprecation notices&lt;/li&gt;
&lt;li&gt;Audit logs&lt;/li&gt;
&lt;li&gt;Policy enforcement&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. Test the Developer Experience
&lt;/h3&gt;

&lt;p&gt;Before rolling out a catalog, ask developers to complete common tasks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Find an existing API for a use case.
- Identify the API owner.
- Check the latest supported version.
- Read request and response examples.
- Request access.
- Report outdated documentation.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If these workflows are slow, the catalog will be harder to adopt.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Plan for Maintenance
&lt;/h3&gt;

&lt;p&gt;A catalog only works if it stays current. Define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who owns catalog quality&lt;/li&gt;
&lt;li&gt;How specs are updated&lt;/li&gt;
&lt;li&gt;Which metadata is required&lt;/li&gt;
&lt;li&gt;How deprecated APIs are handled&lt;/li&gt;
&lt;li&gt;How often APIs are reviewed&lt;/li&gt;
&lt;li&gt;What automation keeps docs in sync&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  API Catalog Tool Selection Matrix
&lt;/h2&gt;

&lt;p&gt;Use this quick comparison when narrowing your options:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Strong fit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Apidog&lt;/td&gt;
&lt;td&gt;Teams that want API cataloging, documentation, testing, mocking, and collaboration together&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DigitalAPI&lt;/td&gt;
&lt;td&gt;Large enterprises with distributed, multi-gateway API environments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RapidAPI Enterprise Hub&lt;/td&gt;
&lt;td&gt;Organizations building private API marketplaces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collibra&lt;/td&gt;
&lt;td&gt;Regulated organizations connecting APIs with data governance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alation&lt;/td&gt;
&lt;td&gt;Data intelligence teams focused on metadata and collaboration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Atlan&lt;/td&gt;
&lt;td&gt;Data-driven enterprises managing metadata and lineage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MuleSoft API Catalog&lt;/td&gt;
&lt;td&gt;Teams already using the MuleSoft ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;API catalog tools help developers discover, reuse, document, and govern APIs across growing software ecosystems. They are especially important when teams manage many services, cloud environments, API gateways, or compliance requirements.&lt;/p&gt;

&lt;p&gt;To choose the right tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Inventory your APIs.
2. Identify where specs and docs currently live.
3. Define required metadata and lifecycle states.
4. Evaluate search, import, governance, and collaboration features.
5. Pilot the tool with real developer workflows.
6. Automate updates so the catalog stays reliable.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tools like Apidog can help teams centralize API documentation, improve discoverability, and connect cataloging with the day-to-day API development workflow.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How the Axios NPM Supply Chain Attack Works (And How to Protect Your API Projects)</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Sun, 21 Jun 2026 13:02:07 +0000</pubDate>
      <link>https://dev.to/preecha/how-the-axios-npm-supply-chain-attack-works-and-how-to-protect-your-api-projects-288h</link>
      <guid>https://dev.to/preecha/how-the-axios-npm-supply-chain-attack-works-and-how-to-protect-your-api-projects-288h</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;On March 31, 2026, attackers compromised the primary maintainer’s npm account for Axios, the popular JavaScript HTTP client with 83 million weekly downloads. They published malicious versions &lt;code&gt;1.14.1&lt;/code&gt; and &lt;code&gt;0.30.4&lt;/code&gt; containing a cross-platform RAT that steals credentials, SSH keys, and cloud tokens from developer machines. Downgrade to Axios &lt;code&gt;1.14.0&lt;/code&gt; or &lt;code&gt;0.30.3&lt;/code&gt;, rotate secrets, and scan for indicators of compromise.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened
&lt;/h2&gt;

&lt;p&gt;Axios is widely used for API clients, frontend-backend communication, integration tests, and developer tooling.&lt;/p&gt;

&lt;p&gt;On March 31, 2026, at &lt;code&gt;00:21 UTC&lt;/code&gt;, a threat actor published &lt;code&gt;axios@1.14.1&lt;/code&gt; through a hijacked maintainer account. The package looked almost identical to the legitimate release. Across 86 files, the meaningful change was in &lt;code&gt;package.json&lt;/code&gt;: a new runtime dependency named &lt;code&gt;plain-crypto-js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That dependency was not used by Axios source code. Its purpose was to execute a malicious &lt;code&gt;postinstall&lt;/code&gt; script during &lt;code&gt;npm install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The malicious Axios versions remained live for roughly two to three hours before npm removed them.&lt;/p&gt;

&lt;p&gt;If you build, test, or automate APIs with Node.js, this attack targeted your dependency chain directly.&lt;/p&gt;

&lt;p&gt;This guide covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How the attack worked&lt;/li&gt;
&lt;li&gt;How to check whether your machine or CI environment was affected&lt;/li&gt;
&lt;li&gt;How to remediate immediately&lt;/li&gt;
&lt;li&gt;How to reduce similar supply chain risk in API workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Attack timeline
&lt;/h2&gt;

&lt;p&gt;The operation happened across an 18-hour window:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;March 30, 05:57 UTC&lt;/strong&gt;: &lt;code&gt;plain-crypto-js@4.2.0&lt;/code&gt; was published as a clean decoy package.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;March 30, 23:59 UTC&lt;/strong&gt;: &lt;code&gt;plain-crypto-js@4.2.1&lt;/code&gt; was published with a malicious &lt;code&gt;postinstall&lt;/code&gt; hook.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;March 31, 00:21 UTC&lt;/strong&gt;: &lt;code&gt;axios@1.14.1&lt;/code&gt; was released using the compromised &lt;code&gt;jasonsaayman&lt;/code&gt; npm account.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;March 31, 01:00 UTC&lt;/strong&gt;: &lt;code&gt;axios@0.30.4&lt;/code&gt; was released, targeting projects still on the &lt;code&gt;0.x&lt;/code&gt; branch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;March 31, ~03:15 UTC&lt;/strong&gt;: npm unpublished both malicious Axios versions after community reports.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;March 31, 04:26 UTC&lt;/strong&gt;: npm published a security-holder stub for &lt;code&gt;plain-crypto-js&lt;/code&gt; to prevent republishing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How the maintainer account compromise showed up
&lt;/h2&gt;

&lt;p&gt;The attacker took over the &lt;code&gt;jasonsaayman&lt;/code&gt; npm account, associated with the primary Axios maintainer, and changed the registered email to &lt;code&gt;ifstap@proton.me&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Key forensic signals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Legitimate Axios releases used GitHub Actions with npm OIDC Trusted Publisher.&lt;/li&gt;
&lt;li&gt;The malicious releases did not include OIDC binding.&lt;/li&gt;
&lt;li&gt;The compromised releases did not include a &lt;code&gt;gitHead&lt;/code&gt; field.&lt;/li&gt;
&lt;li&gt;No matching GitHub commits existed for the malicious package versions.&lt;/li&gt;
&lt;li&gt;The attacker likely used stolen long-lived npm access tokens to publish manually.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For package maintainers, this is the main lesson: releases without CI/CD provenance should be treated as suspicious, especially for high-impact packages.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the dependency injection worked
&lt;/h2&gt;

&lt;p&gt;The attacker did not modify Axios source files.&lt;/p&gt;

&lt;p&gt;Instead, they added a dependency to &lt;code&gt;package.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"plain-crypto-js"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.2.1"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dependency was never imported by Axios. It only needed to be installed.&lt;/p&gt;

&lt;p&gt;During installation, npm executed the dependency’s &lt;code&gt;postinstall&lt;/code&gt; hook, which launched the payload.&lt;/p&gt;

&lt;p&gt;This made the diff look small and easy to miss:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Axios source code appeared unchanged.&lt;/li&gt;
&lt;li&gt;Tests and imports did not reveal the malicious package.&lt;/li&gt;
&lt;li&gt;The payload executed during dependency installation, not runtime execution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What the malicious package did
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dropper execution
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;plain-crypto-js&lt;/code&gt; executed an obfuscated &lt;code&gt;setup.js&lt;/code&gt; file through a &lt;code&gt;postinstall&lt;/code&gt; script.&lt;/p&gt;

&lt;p&gt;The file used two obfuscation layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;XOR cipher using a key derived from &lt;code&gt;"OrDeR_7077"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Base64 encoding with character reversal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After decoding, the dropper detected the host OS and executed a platform-specific path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Platform-specific payload paths
&lt;/h2&gt;

&lt;h3&gt;
  
  
  macOS
&lt;/h3&gt;

&lt;p&gt;The macOS branch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wrote AppleScript to:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/tmp/6202033
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Executed it with:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;osascript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Downloaded the payload to:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/Library/Caches/com.apple.act.mond
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Windows
&lt;/h3&gt;

&lt;p&gt;The Windows branch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copied PowerShell to:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;PROGRAMDATA&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nx"&gt;\wt.exe&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Executed a VBScript dropper with:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;cscript&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Linux
&lt;/h3&gt;

&lt;p&gt;The Linux branch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Downloaded a Python RAT to:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/tmp/ld.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Executed it with:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;nohup &lt;/span&gt;python3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Command-and-control endpoints
&lt;/h2&gt;

&lt;p&gt;The payload contacted a command-and-control server using platform-specific POST paths:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;macOS: &lt;code&gt;packages.npm.org/product0&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Windows: &lt;code&gt;packages.npm.org/product1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Linux: &lt;code&gt;packages.npm.org/product2&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Known network indicators:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sfrclak.com
142.11.206.73
http://sfrclak.com:8000/6202033
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  RAT capabilities
&lt;/h2&gt;

&lt;p&gt;The deployed remote access trojan supported:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Arbitrary shell command execution&lt;/li&gt;
&lt;li&gt;File system enumeration&lt;/li&gt;
&lt;li&gt;File exfiltration&lt;/li&gt;
&lt;li&gt;Process listing&lt;/li&gt;
&lt;li&gt;Process injection&lt;/li&gt;
&lt;li&gt;In-memory binary injection&lt;/li&gt;
&lt;li&gt;60-second beaconing to C2 infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a developer machine, that means the attacker could access:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.env&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;npm tokens&lt;/li&gt;
&lt;li&gt;GitHub tokens&lt;/li&gt;
&lt;li&gt;SSH keys&lt;/li&gt;
&lt;li&gt;Cloud provider credentials&lt;/li&gt;
&lt;li&gt;Database credentials&lt;/li&gt;
&lt;li&gt;API keys&lt;/li&gt;
&lt;li&gt;Secrets stored in environment variables&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Anti-forensics behavior
&lt;/h2&gt;

&lt;p&gt;After execution, the dropper attempted to hide evidence by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Deleting &lt;code&gt;setup.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Deleting the malicious &lt;code&gt;package.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Renaming a pre-staged &lt;code&gt;package.md&lt;/code&gt; reporting version &lt;code&gt;4.2.0&lt;/code&gt; to &lt;code&gt;package.json&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This caused &lt;code&gt;npm list&lt;/code&gt; to potentially show &lt;code&gt;plain-crypto-js@4.2.0&lt;/code&gt;, even though &lt;code&gt;4.2.1&lt;/code&gt; had already executed.&lt;/p&gt;

&lt;p&gt;Do not rely only on current package metadata to determine whether the payload ran.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attribution
&lt;/h2&gt;

&lt;p&gt;Google Threat Intelligence Group attributed the Axios attack to UNC1069, a suspected North Korean threat actor.&lt;/p&gt;

&lt;p&gt;The macOS malware showed significant overlap with WAVESHAPER, a C++ backdoor tracked by Mandiant in February 2026.&lt;/p&gt;

&lt;p&gt;The operation matched known supply chain attack patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compromise a maintainer or publishing token&lt;/li&gt;
&lt;li&gt;Target a high-volume developer package&lt;/li&gt;
&lt;li&gt;Execute during installation&lt;/li&gt;
&lt;li&gt;Steal credentials and cloud access&lt;/li&gt;
&lt;li&gt;Clean up local artifacts to slow investigation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Check whether you are affected
&lt;/h2&gt;

&lt;p&gt;Run these checks on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developer machines&lt;/li&gt;
&lt;li&gt;CI runners&lt;/li&gt;
&lt;li&gt;Build agents&lt;/li&gt;
&lt;li&gt;Containers used during the attack window&lt;/li&gt;
&lt;li&gt;Any system that ran &lt;code&gt;npm install&lt;/code&gt; or &lt;code&gt;npm ci&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The critical window was approximately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;March 31, 2026 00:21 UTC to 03:15 UTC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 1: Check installed Axios versions
&lt;/h2&gt;

&lt;p&gt;From each project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm list axios 2&amp;gt;/dev/null | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s2"&gt;"1&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;14&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;1|0&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;30&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;4"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this returns output, the project resolved a compromised version.&lt;/p&gt;

&lt;p&gt;Also check lockfiles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'"axios": "1\.14\.1"|"axios": "0\.30\.4"|axios@1\.14\.1|axios@0\.30\.4'&lt;/span&gt; package-lock.json yarn.lock pnpm-lock.yaml 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Check for the malicious dependency
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls &lt;/span&gt;node_modules/plain-crypto-js 2&amp;gt;/dev/null &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"POTENTIALLY AFFECTED"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The directory’s presence is a strong signal that the malicious dependency was installed.&lt;/p&gt;

&lt;p&gt;Because the dropper attempted cleanup, absence of this directory does not fully prove safety.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Check platform artifacts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  macOS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /Library/Caches/com.apple.act.mond 2&amp;gt;/dev/null
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /tmp/6202033 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Linux
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /tmp/ld.py 2&amp;gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Windows PowerShell
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Test-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;PROGRAMDATA&lt;/span&gt;&lt;span class="s2"&gt;\wt.exe"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If any of these artifacts exist, treat the host as compromised.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Check network indicators
&lt;/h2&gt;

&lt;p&gt;Search firewall, proxy, EDR, DNS, and CI runner logs for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sfrclak.com
142.11.206.73
http://sfrclak.com:8000/6202033
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If possible, block the C2 domain and IP at the network level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Review CI/CD logs
&lt;/h2&gt;

&lt;p&gt;Review pipeline runs during the exposure window.&lt;/p&gt;

&lt;p&gt;Look for commands such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm ci
yarn &lt;span class="nb"&gt;install
&lt;/span&gt;pnpm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any install that resolved &lt;code&gt;axios@1.14.1&lt;/code&gt; or &lt;code&gt;axios@0.30.4&lt;/code&gt; could have executed the payload.&lt;/p&gt;

&lt;p&gt;Pay special attention to CI jobs that had access to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deployment credentials&lt;/li&gt;
&lt;li&gt;npm publishing tokens&lt;/li&gt;
&lt;li&gt;Cloud credentials&lt;/li&gt;
&lt;li&gt;SSH deploy keys&lt;/li&gt;
&lt;li&gt;GitHub Actions secrets&lt;/li&gt;
&lt;li&gt;Container registry credentials&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Immediate remediation
&lt;/h2&gt;

&lt;p&gt;If you find any indicator of compromise, assume the affected system and its secrets are compromised.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Downgrade Axios
&lt;/h2&gt;

&lt;p&gt;For the &lt;code&gt;1.x&lt;/code&gt; branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;axios@1.14.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the &lt;code&gt;0.x&lt;/code&gt; branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;axios@0.30.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm list axios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Add package overrides
&lt;/h2&gt;

&lt;p&gt;Use overrides to prevent transitive resolution to the compromised versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  npm
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"overrides"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"axios"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.14.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Yarn
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"resolutions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"axios"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.14.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For projects that must stay on the &lt;code&gt;0.x&lt;/code&gt; branch, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"overrides"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"axios"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.30.3"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Remove the malicious dependency
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; node_modules/plain-crypto-js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then reinstall from a clean lockfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; node_modules
npm ci
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your lockfile references the malicious versions, update it after pinning Axios.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Rotate secrets
&lt;/h2&gt;

&lt;p&gt;If the payload executed, rotate all credentials that may have been accessible from the host.&lt;/p&gt;

&lt;p&gt;Prioritize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;npm tokens&lt;/li&gt;
&lt;li&gt;GitHub tokens&lt;/li&gt;
&lt;li&gt;GitLab tokens&lt;/li&gt;
&lt;li&gt;SSH keys&lt;/li&gt;
&lt;li&gt;AWS credentials&lt;/li&gt;
&lt;li&gt;GCP credentials&lt;/li&gt;
&lt;li&gt;Azure credentials&lt;/li&gt;
&lt;li&gt;API keys in &lt;code&gt;.env&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;Database credentials&lt;/li&gt;
&lt;li&gt;Container registry credentials&lt;/li&gt;
&lt;li&gt;CI/CD deployment tokens&lt;/li&gt;
&lt;li&gt;Secrets stored in shell profiles or environment variables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not rotate secrets from the compromised host. Use a clean machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Block known C2 indicators
&lt;/h2&gt;

&lt;p&gt;As a temporary local block on Unix-like systems:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"0.0.0.0 sfrclak.com"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; /etc/hosts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also block at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DNS resolver&lt;/li&gt;
&lt;li&gt;Firewall&lt;/li&gt;
&lt;li&gt;Proxy&lt;/li&gt;
&lt;li&gt;EDR&lt;/li&gt;
&lt;li&gt;Cloud egress controls&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Rebuild compromised machines
&lt;/h2&gt;

&lt;p&gt;If RAT artifacts are found, do not trust the system.&lt;/p&gt;

&lt;p&gt;A RAT with shell execution and file access can modify files, install persistence, and tamper with tooling.&lt;/p&gt;

&lt;p&gt;Recommended response:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Preserve evidence if your incident response process requires it.&lt;/li&gt;
&lt;li&gt;Remove the host from the network.&lt;/li&gt;
&lt;li&gt;Rebuild from a known-good image.&lt;/li&gt;
&lt;li&gt;Reinstall dependencies from clean lockfiles.&lt;/li&gt;
&lt;li&gt;Rotate secrets from a clean environment.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Long-term defenses for JavaScript and API teams
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Pin exact dependency versions
&lt;/h2&gt;

&lt;p&gt;The attack benefited from semver ranges.&lt;/p&gt;

&lt;p&gt;If your &lt;code&gt;package.json&lt;/code&gt; used this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"axios"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.14.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;npm could resolve &lt;code&gt;1.14.1&lt;/code&gt; during the attack window.&lt;/p&gt;

&lt;p&gt;Prefer exact versions for critical dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"axios"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.14.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also commit your lockfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add package-lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In CI, prefer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm ci
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;over:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;npm ci&lt;/code&gt; installs from the lockfile and fails if the lockfile and &lt;code&gt;package.json&lt;/code&gt; are out of sync.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disable install scripts where possible
&lt;/h2&gt;

&lt;p&gt;The malicious package executed through &lt;code&gt;postinstall&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In CI/CD, test whether your project can install with scripts disabled:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm ci &lt;span class="nt"&gt;--ignore-scripts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also set this in &lt;code&gt;.npmrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;ignore-scripts&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This may break packages that require native compilation or setup scripts, so validate before enforcing globally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Audit dependencies in CI
&lt;/h2&gt;

&lt;p&gt;Add dependency checks to your pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm audit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also run third-party supply chain scanners where appropriate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx socket-security/cli audit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use audit results as a deployment gate for high and critical findings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify package provenance
&lt;/h2&gt;

&lt;p&gt;npm supports package provenance through Sigstore.&lt;/p&gt;

&lt;p&gt;Check signatures with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm audit signatures
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compromised Axios versions lacked OIDC provenance. For high-impact dependencies, missing provenance on a new release should trigger review before adoption.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitor for unexpected dependency changes
&lt;/h2&gt;

&lt;p&gt;Add a CI step that fails when lockfiles change unexpectedly.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff &lt;span class="nt"&gt;--exit-code&lt;/span&gt; package-lock.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For pull requests, review:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New runtime dependencies&lt;/li&gt;
&lt;li&gt;New transitive dependencies&lt;/li&gt;
&lt;li&gt;Packages with install scripts&lt;/li&gt;
&lt;li&gt;Packages with low download counts&lt;/li&gt;
&lt;li&gt;Packages published very recently&lt;/li&gt;
&lt;li&gt;Packages without repository metadata&lt;/li&gt;
&lt;li&gt;Packages without provenance&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reduce your HTTP client dependency surface
&lt;/h2&gt;

&lt;p&gt;API testing workflows often add HTTP client dependencies such as Axios, &lt;code&gt;node-fetch&lt;/code&gt;, or &lt;code&gt;got&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For production code, those libraries may still be appropriate. But for API testing, debugging, and documentation, you can often reduce npm dependency exposure by using a dedicated API platform.&lt;/p&gt;

&lt;p&gt;Apidog provides a built-in HTTP client for API testing, debugging, mocking, and documentation. That means you can avoid installing third-party HTTP clients in your API testing stack.&lt;/p&gt;

&lt;p&gt;Practical ways to reduce dependency surface:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Apidog’s visual test builder instead of Axios-based test scripts.&lt;/li&gt;
&lt;li&gt;Use Apidog’s request inspector instead of custom debugging clients.&lt;/li&gt;
&lt;li&gt;Use Apidog mock servers instead of building mock endpoints with Express and Axios.&lt;/li&gt;
&lt;li&gt;Use Apidog CLI for automated API tests in CI/CD.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This does not remove all supply chain risk, but it removes one common npm dependency path from API testing workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison: HTTP client approaches
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Supply chain risk&lt;/th&gt;
&lt;th&gt;Maintenance burden&lt;/th&gt;
&lt;th&gt;Testing capability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Axios + custom scripts&lt;/td&gt;
&lt;td&gt;High, because it depends on third-party npm packages&lt;/td&gt;
&lt;td&gt;High, because versions and transitive dependencies must be managed&lt;/td&gt;
&lt;td&gt;Manual setup required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js native &lt;code&gt;fetch&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Low, because it is built into the runtime&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Limited testing features&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apidog built-in client&lt;/td&gt;
&lt;td&gt;No npm HTTP client dependency&lt;/td&gt;
&lt;td&gt;Platform-managed&lt;/td&gt;
&lt;td&gt;API testing, mocking, debugging, and docs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;curl&lt;/code&gt; / &lt;code&gt;httpie&lt;/code&gt; scripts&lt;/td&gt;
&lt;td&gt;Low, because they are system-level tools&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Limited automation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What this means for npm security
&lt;/h2&gt;

&lt;p&gt;The npm trust model depends heavily on maintainer account security.&lt;/p&gt;

&lt;p&gt;A single compromised maintainer credential or long-lived token can affect millions of downstream installs.&lt;/p&gt;

&lt;p&gt;Important ecosystem-level defenses include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OIDC-based publishing instead of long-lived npm tokens&lt;/li&gt;
&lt;li&gt;Mandatory provenance for high-impact packages&lt;/li&gt;
&lt;li&gt;Two-person approval for critical releases&lt;/li&gt;
&lt;li&gt;Better detection for suspicious dependency additions&lt;/li&gt;
&lt;li&gt;Safer handling of install scripts&lt;/li&gt;
&lt;li&gt;Runtime permission scoping similar to Deno’s model&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For application teams, the takeaway is simpler: treat every dependency as an execution path.&lt;/p&gt;

&lt;p&gt;If it can run during install, it can become part of your attack surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Is Axios safe to use now?
&lt;/h2&gt;

&lt;p&gt;Yes. Axios &lt;code&gt;1.14.0&lt;/code&gt; and &lt;code&gt;0.30.3&lt;/code&gt; are clean according to the provided incident details. The compromised versions were &lt;code&gt;1.14.1&lt;/code&gt; and &lt;code&gt;0.30.4&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Verify your installed version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm list axios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also check your lockfile.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I know if the RAT ran?
&lt;/h2&gt;

&lt;p&gt;Check for these artifacts:&lt;/p&gt;

&lt;h3&gt;
  
  
  macOS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/Library/Caches/com.apple.act.mond
/tmp/6202033
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Linux
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/tmp/ld.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Windows
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;PROGRAMDATA&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="nx"&gt;\wt.exe&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also check for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node_modules/plain-crypto-js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the dropper attempted cleanup, missing artifacts do not guarantee the host was safe if it installed a compromised version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should I stop using Axios?
&lt;/h2&gt;

&lt;p&gt;Not necessarily.&lt;/p&gt;

&lt;p&gt;Axios remains a widely used HTTP client. The better question is where you need it.&lt;/p&gt;

&lt;p&gt;For application code, evaluate Axios against alternatives like native &lt;code&gt;fetch&lt;/code&gt; in Node.js 18+.&lt;/p&gt;

&lt;p&gt;For API testing workflows, consider moving requests into tools like Apidog so your tests do not require an npm HTTP client dependency.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I reduce supply chain risk in Node.js projects?
&lt;/h2&gt;

&lt;p&gt;Start with these controls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pin exact dependency versions.&lt;/li&gt;
&lt;li&gt;Commit lockfiles.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;npm ci&lt;/code&gt; in CI/CD.&lt;/li&gt;
&lt;li&gt;Test &lt;code&gt;npm ci --ignore-scripts&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Audit dependencies on every build.&lt;/li&gt;
&lt;li&gt;Verify package provenance with &lt;code&gt;npm audit signatures&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Review new transitive dependencies.&lt;/li&gt;
&lt;li&gt;Minimize unnecessary packages.&lt;/li&gt;
&lt;li&gt;Rotate tokens regularly.&lt;/li&gt;
&lt;li&gt;Prefer OIDC publishing over long-lived npm tokens.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Was this related to the Claude Code source leak?
&lt;/h2&gt;

&lt;p&gt;Both events happened on March 31, 2026, but they were unrelated.&lt;/p&gt;

&lt;p&gt;The Axios incident was a deliberate supply chain compromise attributed to a suspected state-sponsored threat actor.&lt;/p&gt;

&lt;p&gt;The Claude Code leak resulted from a Bun build tool issue that shipped source maps in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who was behind the Axios attack?
&lt;/h2&gt;

&lt;p&gt;Google Threat Intelligence Group attributed the attack to UNC1069, a suspected North Korean threat actor.&lt;/p&gt;

&lt;p&gt;The macOS malware shared significant overlap with WAVESHAPER, a C++ backdoor tracked by Mandiant.&lt;/p&gt;

&lt;h2&gt;
  
  
  How many developers were affected?
&lt;/h2&gt;

&lt;p&gt;npm has not published official impact numbers in the provided incident details.&lt;/p&gt;

&lt;p&gt;The malicious versions were live for roughly two to three hours. Given Axios’ 83 million weekly downloads, the potential exposure was significant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can Apidog help prevent this type of issue?
&lt;/h2&gt;

&lt;p&gt;Apidog can reduce one specific attack path: npm HTTP client dependencies in API testing workflows.&lt;/p&gt;

&lt;p&gt;By using Apidog’s built-in HTTP client for testing, debugging, mocking, and documentation, you do not need to install Axios, &lt;code&gt;node-fetch&lt;/code&gt;, or similar libraries just to run API tests.&lt;/p&gt;

&lt;p&gt;That reduces your dependency surface, though it should be combined with broader supply chain controls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Axios attack used a compromised maintainer account to publish malicious versions.&lt;/li&gt;
&lt;li&gt;The affected versions were &lt;code&gt;axios@1.14.1&lt;/code&gt; and &lt;code&gt;axios@0.30.4&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The malicious dependency &lt;code&gt;plain-crypto-js&lt;/code&gt; executed through a &lt;code&gt;postinstall&lt;/code&gt; hook.&lt;/li&gt;
&lt;li&gt;The payload deployed a cross-platform RAT targeting macOS, Windows, and Linux.&lt;/li&gt;
&lt;li&gt;Treat affected machines as compromised and rotate secrets from a clean environment.&lt;/li&gt;
&lt;li&gt;Pin exact versions and commit lockfiles.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;npm ci&lt;/code&gt;, and test &lt;code&gt;--ignore-scripts&lt;/code&gt; in CI/CD.&lt;/li&gt;
&lt;li&gt;Verify provenance with &lt;code&gt;npm audit signatures&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Reduce unnecessary npm dependencies in API testing workflows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every package in &lt;code&gt;node_modules&lt;/code&gt; is a trust decision. Make those decisions intentionally.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What the Claude Code Source Leak Reveals About AI Coding Tool Architecture</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Sun, 21 Jun 2026 01:01:42 +0000</pubDate>
      <link>https://dev.to/preecha/what-the-claude-code-source-leak-reveals-about-ai-coding-tool-architecture-4o1c</link>
      <guid>https://dev.to/preecha/what-the-claude-code-source-leak-reveals-about-ai-coding-tool-architecture-4o1c</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Anthropic accidentally shipped a &lt;code&gt;.map&lt;/code&gt; file with the Claude Code npm package, exposing the complete readable source code of its CLI tool. The leak revealed anti-distillation mechanisms with fake tool injection, a frustration-detection regex engine, an “undercover mode” that hides AI authorship in open-source commits, client attestation, and an unreleased autonomous agent mode called KAIROS. Here’s what API developers can learn from how AI coding tools work under the hood.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;On March 31, 2026, security researcher Chaofan Shou discovered that Anthropic shipped a source map file (&lt;code&gt;.map&lt;/code&gt;) with the Claude Code npm package.&lt;/p&gt;

&lt;p&gt;Source maps map minified production code back to readable source code. They are useful for debugging, but they should not be included in production packages unless intentionally published.&lt;/p&gt;

&lt;p&gt;In this case, the source map exposed the complete Claude Code source code, including comments, internal codenames, prompt templates, feature flags, and architectural details.&lt;/p&gt;

&lt;p&gt;The discovery reached #1 on Hacker News and spread quickly across Reddit, Twitter, and developer forums. Anthropic removed the package, but the code had already been mirrored and analyzed.&lt;/p&gt;

&lt;p&gt;Whether you use Claude Code, Cursor, GitHub Copilot, or an API development platform like Apidog, the leak is useful because it shows how modern AI coding tools actually behave: what they send, what they hide, how they enforce client authenticity, and how they prepare for autonomous operation.&lt;/p&gt;

&lt;p&gt;This article focuses on the technical findings and what API developers can do with those lessons.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the source code leaked
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Root cause: a Bun build tool bug
&lt;/h3&gt;

&lt;p&gt;Claude Code is built with Bun, an alternative JavaScript runtime.&lt;/p&gt;

&lt;p&gt;On March 11, 2026, a bug was filed against Bun (&lt;code&gt;oven-sh/bun#28001&lt;/code&gt;) reporting that source maps were being served in production mode even though Bun’s documentation said they should be disabled.&lt;/p&gt;

&lt;p&gt;Anthropic’s build pipeline triggered this bug. When the Claude Code npm package was published, the &lt;code&gt;.map&lt;/code&gt; file was included in the distributed package.&lt;/p&gt;

&lt;p&gt;That meant anyone could inspect the package and read the unminified source.&lt;/p&gt;

&lt;p&gt;For example, this kind of workflow would expose package contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm pack @anthropic-ai/claude-code
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-tf&lt;/span&gt; anthropic-ai-claude-code-&lt;span class="k"&gt;*&lt;/span&gt;.tgz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a source map is included, developers can often recover readable source from the minified bundle.&lt;/p&gt;

&lt;h3&gt;
  
  
  What was exposed
&lt;/h3&gt;

&lt;p&gt;The leak reportedly included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complete TypeScript source across modules&lt;/li&gt;
&lt;li&gt;Internal comments explaining design decisions&lt;/li&gt;
&lt;li&gt;Feature flags and experimental configurations&lt;/li&gt;
&lt;li&gt;System prompt templates and safety mechanisms&lt;/li&gt;
&lt;li&gt;Internal codenames for unreleased features&lt;/li&gt;
&lt;li&gt;Performance optimization details with specific metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was not a partial leak or a sanitized open-source release. It was production source with internal engineering context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anti-distillation: protecting against model theft
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Fake tool injection
&lt;/h3&gt;

&lt;p&gt;One of the most discussed findings was Claude Code’s anti-distillation system.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;claude.ts&lt;/code&gt;, when the &lt;code&gt;ANTI_DISTILLATION_CC&lt;/code&gt; flag is enabled, the client sends this field in API requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;anti_distillation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fake_tools&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This instructs Anthropic’s server to inject decoy tool definitions into the system prompt.&lt;/p&gt;

&lt;p&gt;The goal is to make captured API traffic less useful for competitors trying to train a model on Claude’s tool-use behavior.&lt;/p&gt;

&lt;p&gt;A simplified version of the pattern looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;claude&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;anti_distillation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fake_tools&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a third party records the prompt and tool definitions, the captured data may include fake tools that do not exist. A model trained on that data could learn invalid capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connector-text summarization
&lt;/h3&gt;

&lt;p&gt;A second anti-distillation mechanism appeared in &lt;code&gt;betas.ts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Instead of returning all assistant text between tool calls directly, the server can buffer the text, summarize it, and return a signed summary.&lt;/p&gt;

&lt;p&gt;On later turns, the original text can be restored from the signature. But someone passively recording API traffic only sees summaries, not the full reasoning-like connector text.&lt;/p&gt;

&lt;p&gt;The pattern is roughly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assistant text between tool calls
        ↓
server-side summarization
        ↓
summary + cryptographic signature
        ↓
restore original text later when needed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The purpose is to reduce how much useful behavioral data is available to traffic recorders.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical bypasses
&lt;/h3&gt;

&lt;p&gt;The analysis also identified bypass paths:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A man-in-the-middle proxy could strip the &lt;code&gt;anti_distillation&lt;/code&gt; field before requests reach the server.&lt;/li&gt;
&lt;li&gt;Setting &lt;code&gt;CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS&lt;/code&gt; disables the experimental beta system.&lt;/li&gt;
&lt;li&gt;These protections mainly defend against passive traffic recording, not active API usage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the takeaway is not “anti-distillation is impossible to bypass.” The takeaway is that vendors are adding protocol-level defenses to make model copying more expensive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Undercover mode: hiding AI authorship
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What the mode does
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;undercover.ts&lt;/code&gt; file contained one of the most controversial findings.&lt;/p&gt;

&lt;p&gt;When Claude Code operates in non-Anthropic repositories, it activates behavior that prevents outputs from including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Internal codenames such as &lt;code&gt;Capybara&lt;/code&gt; or &lt;code&gt;Tengu&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Internal Slack channel names&lt;/li&gt;
&lt;li&gt;Internal repository names&lt;/li&gt;
&lt;li&gt;The phrase &lt;code&gt;Claude Code&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The source comment was explicit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;There is NO force-OFF. This guards against model codename leaks.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why developers should care
&lt;/h3&gt;

&lt;p&gt;The stated goal is to prevent leakage of internal Anthropic names. But the implementation also prevents the tool from identifying itself.&lt;/p&gt;

&lt;p&gt;That matters for open-source projects with policies requiring disclosure of AI-generated code.&lt;/p&gt;

&lt;p&gt;If an AI coding tool is designed not to mention its involvement, maintainers have a harder time enforcing disclosure policies.&lt;/p&gt;

&lt;p&gt;For teams, the practical step is to define disclosure requirements outside the tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## AI-generated code policy&lt;/span&gt;

Contributors must disclose when code, tests, documentation, or review comments
were materially generated by AI tools.

Disclosure must be included in the pull request description.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not rely on the coding assistant to self-identify.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frustration detection via regex
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;userPromptKeywords.ts&lt;/code&gt; file implemented frustration detection using regex pattern matching.&lt;/p&gt;

&lt;p&gt;The system scans user prompts for profanity and emotionally charged language to infer when a user may be frustrated with Claude Code’s responses.&lt;/p&gt;

&lt;p&gt;A simplified version of that approach looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;frustrationPatterns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;this is broken&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;/i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;wtf&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;/i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;why won't this work&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;/i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isUserFrustrated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;frustrationPatterns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&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;h3&gt;
  
  
  Why regex instead of an LLM?
&lt;/h3&gt;

&lt;p&gt;Several developers pointed out the irony: Anthropic builds advanced language models, but uses regex to detect user emotion.&lt;/p&gt;

&lt;p&gt;The engineering reason is practical:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Regex is fast.&lt;/li&gt;
&lt;li&gt;Regex is cheap.&lt;/li&gt;
&lt;li&gt;Regex does not require another model call.&lt;/li&gt;
&lt;li&gt;Regex can run on every prompt without adding much latency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For hot-path product telemetry, this is a common trade-off.&lt;/p&gt;

&lt;p&gt;The implementation question for developers is not whether regex is technically impressive. It is whether your team is comfortable with AI coding tools analyzing emotional signals in prompts.&lt;/p&gt;

&lt;p&gt;A practical evaluation checklist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; Does the tool inspect user prompts for telemetry?
&lt;span class="p"&gt;-&lt;/span&gt; Can telemetry be disabled?
&lt;span class="p"&gt;-&lt;/span&gt; Is prompt telemetry documented?
&lt;span class="p"&gt;-&lt;/span&gt; Is data used for product analytics, model training, or both?
&lt;span class="p"&gt;-&lt;/span&gt; Are enterprise controls available?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Native client attestation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cryptographic request verification
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;system.ts&lt;/code&gt;, Claude Code API requests include a placeholder header value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cch=554eb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bun’s native HTTP stack, written in Zig, overwrites this placeholder with a computed hash before the request leaves the client.&lt;/p&gt;

&lt;p&gt;Anthropic’s servers can then validate that hash to verify that the request came from the legitimate Claude Code binary rather than a fork, wrapper, or proxy.&lt;/p&gt;

&lt;p&gt;At a high level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Claude Code binary
        ↓
request contains placeholder
        ↓
native HTTP layer computes hash
        ↓
server validates attestation
        ↓
request accepted or rejected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why this matters
&lt;/h3&gt;

&lt;p&gt;This is a client-authenticity mechanism.&lt;/p&gt;

&lt;p&gt;It can be used to enforce that only approved clients access a SaaS API. Similar patterns exist in mobile API security, where app attestation helps prevent unauthorized clients from calling backend APIs.&lt;/p&gt;

&lt;p&gt;For API developers, the lesson is clear: authentication is not only about users. Sometimes you also need to authenticate the client.&lt;/p&gt;

&lt;p&gt;Common API client verification layers include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API keys&lt;/li&gt;
&lt;li&gt;OAuth clients&lt;/li&gt;
&lt;li&gt;mTLS&lt;/li&gt;
&lt;li&gt;Certificate pinning&lt;/li&gt;
&lt;li&gt;Device or app attestation&lt;/li&gt;
&lt;li&gt;Signed request headers&lt;/li&gt;
&lt;li&gt;Replay protection with timestamps and nonces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simplified signed-request flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;node:crypto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;signRequest&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&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;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Server-side verification should recompute the signature and reject mismatches.&lt;/p&gt;

&lt;h2&gt;
  
  
  KAIROS: the unreleased autonomous agent mode
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What the code showed
&lt;/h3&gt;

&lt;p&gt;References throughout the leaked codebase pointed to an unreleased feature-gated mode called KAIROS.&lt;/p&gt;

&lt;p&gt;The discovered scaffolding included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;/dream&lt;/code&gt; skill for “nightly memory distillation”&lt;/li&gt;
&lt;li&gt;Daily append-only logging&lt;/li&gt;
&lt;li&gt;GitHub webhook subscriptions&lt;/li&gt;
&lt;li&gt;Background daemon workers&lt;/li&gt;
&lt;li&gt;5-minute cron refresh intervals&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What this implies
&lt;/h3&gt;

&lt;p&gt;KAIROS appears to be an always-on coding agent mode.&lt;/p&gt;

&lt;p&gt;Instead of waiting for direct user prompts, an agent like this could monitor repositories, react to events, and perform background tasks.&lt;/p&gt;

&lt;p&gt;A simplified architecture would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GitHub webhook
      ↓
agent event queue
      ↓
background worker
      ↓
repository analysis
      ↓
suggested or automated code changes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This matches the broader direction of AI coding tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Copilot Agent Mode&lt;/li&gt;
&lt;li&gt;Cursor background processing&lt;/li&gt;
&lt;li&gt;Google Agent Smith&lt;/li&gt;
&lt;li&gt;Claude Code KAIROS scaffolding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key implementation concern for API teams is drift.&lt;/p&gt;

&lt;p&gt;If an autonomous agent changes endpoint code, what else changes?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenAPI specification&lt;/li&gt;
&lt;li&gt;Tests&lt;/li&gt;
&lt;li&gt;Mock server behavior&lt;/li&gt;
&lt;li&gt;SDKs&lt;/li&gt;
&lt;li&gt;Documentation&lt;/li&gt;
&lt;li&gt;Changelog&lt;/li&gt;
&lt;li&gt;Contract tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If those artifacts live in disconnected tools, autonomous changes can break your API lifecycle.&lt;/p&gt;

&lt;p&gt;A safer workflow is to enforce contract checks in CI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;API Contract Check&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contract&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Validate OpenAPI spec&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx @redocly/cli lint openapi.yaml&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run API tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whether a human or AI agent opens the pull request, the same checks should apply.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance optimizations exposed
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Terminal rendering with game-engine-style techniques
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;ink/screen.ts&lt;/code&gt; and &lt;code&gt;ink/optimizer.ts&lt;/code&gt; files showed that Claude Code uses unusually optimized terminal rendering techniques.&lt;/p&gt;

&lt;p&gt;The exposed techniques included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Int32Array&lt;/code&gt;-backed character pools&lt;/li&gt;
&lt;li&gt;Memory-efficient screen buffers&lt;/li&gt;
&lt;li&gt;Patch optimization during token streaming&lt;/li&gt;
&lt;li&gt;Character-width calculation reductions of about 50x&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This explains why Claude Code can feel responsive during long streaming outputs.&lt;/p&gt;

&lt;p&gt;For CLI developers, the lesson is that terminal rendering can become a bottleneck. If your tool streams many updates, avoid repainting everything.&lt;/p&gt;

&lt;p&gt;A basic inefficient renderer might do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;x1b[2J&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;x1b[0f&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// clear screen&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;output&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;A more efficient approach computes and writes only changed regions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;diffLines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&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="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;changed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;changed&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;The principle: stream less, diff more.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompt cache economics
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;promptCacheBreakDetection.ts&lt;/code&gt; tracked 14 distinct cache-break vectors with “sticky latches” that prevent mode toggles from invalidating cached prompts.&lt;/p&gt;

&lt;p&gt;Prompt caching matters because cache misses force the provider to reprocess the system prompt and conversation context.&lt;/p&gt;

&lt;p&gt;For high-volume AI tools, unnecessary cache invalidation can create major cost and latency problems.&lt;/p&gt;

&lt;p&gt;If you build AI workflows, track cache-break causes explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;CacheBreakReason&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system_prompt_changed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tool_schema_changed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;model_changed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;temperature_changed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;context_reset&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;recordCacheBreak&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CacheBreakReason&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;prompt_cache_break&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="nx"&gt;reason&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;Make cache invalidation observable. Otherwise, cost regressions are hard to debug.&lt;/p&gt;

&lt;h3&gt;
  
  
  The autocompact failure cascade
&lt;/h3&gt;

&lt;p&gt;A comment in &lt;code&gt;autoCompact.ts&lt;/code&gt; described a production issue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1,279 sessions had 50+ consecutive failures (up to 3,272) in a single session,
wasting ~250K API calls/day globally.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fix was to cap consecutive autocompact failures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The lesson is simple: every retry loop needs a limit.&lt;/p&gt;

&lt;p&gt;Bad pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;compactContext&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;Safer pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MAX_RETRIES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;MAX_RETRIES&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;compactContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;MAX_RETRIES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&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;At small scale, retry bugs are annoying. At AI scale, they can burn hundreds of thousands of API calls per day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security hardening details
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Bash security: 23 numbered checks
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;bashSecurity.ts&lt;/code&gt; implemented 23 numbered security checks for shell command execution.&lt;/p&gt;

&lt;p&gt;The checks included defenses against:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zsh builtin exploitation&lt;/li&gt;
&lt;li&gt;Unicode zero-width space injection&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;IFS&lt;/code&gt; null-byte injection&lt;/li&gt;
&lt;li&gt;Additional issues discovered during HackerOne security review&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is more thorough than basic command sanitization.&lt;/p&gt;

&lt;p&gt;For AI coding tools, shell execution is one of the highest-risk capabilities. If an assistant can generate and run commands, it can potentially affect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Source code&lt;/li&gt;
&lt;li&gt;Local secrets&lt;/li&gt;
&lt;li&gt;Databases&lt;/li&gt;
&lt;li&gt;Cloud credentials&lt;/li&gt;
&lt;li&gt;CI/CD configuration&lt;/li&gt;
&lt;li&gt;Production infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A minimal shell execution policy should include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; Deny dangerous commands by default.
&lt;span class="p"&gt;-&lt;/span&gt; Require confirmation for filesystem changes.
&lt;span class="p"&gt;-&lt;/span&gt; Require confirmation for network calls.
&lt;span class="p"&gt;-&lt;/span&gt; Block access to secret files.
&lt;span class="p"&gt;-&lt;/span&gt; Normalize Unicode before validation.
&lt;span class="p"&gt;-&lt;/span&gt; Log executed commands.
&lt;span class="p"&gt;-&lt;/span&gt; Run commands in a sandbox when possible.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example denylist logic is not enough, but it is a starting point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blocked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;rm&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+-rf&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\/&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;sudo&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;chmod&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+777&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;curl&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;\|\s&lt;/span&gt;&lt;span class="sr"&gt;*sh&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="sr"&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;function&lt;/span&gt; &lt;span class="nf"&gt;isBlockedCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;blocked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&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;For production-grade tools, combine validation, sandboxing, explicit user approval, and audit logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What API developers should do next
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Audit what your AI coding tools send
&lt;/h3&gt;

&lt;p&gt;Do not treat AI coding assistants as local-only tools unless the vendor explicitly documents that behavior.&lt;/p&gt;

&lt;p&gt;Check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; Are prompts sent to external servers?
&lt;span class="p"&gt;-&lt;/span&gt; Are files uploaded for context?
&lt;span class="p"&gt;-&lt;/span&gt; Are tool outputs sent back to the provider?
&lt;span class="p"&gt;-&lt;/span&gt; Is telemetry enabled?
&lt;span class="p"&gt;-&lt;/span&gt; Can telemetry be disabled?
&lt;span class="p"&gt;-&lt;/span&gt; Are enterprise privacy controls available?
&lt;span class="p"&gt;-&lt;/span&gt; Are generated commits or PRs labeled as AI-assisted?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For sensitive API work, pay special attention to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.env&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;API keys&lt;/li&gt;
&lt;li&gt;OAuth client secrets&lt;/li&gt;
&lt;li&gt;Internal endpoint URLs&lt;/li&gt;
&lt;li&gt;Private OpenAPI specs&lt;/li&gt;
&lt;li&gt;Customer data in test fixtures&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Treat your build toolchain as an attack surface
&lt;/h3&gt;

&lt;p&gt;Anthropic’s source leaked because of a build tool issue. On the same day, Axios was compromised through npm account hijacking.&lt;/p&gt;

&lt;p&gt;Different causes, same lesson: the development supply chain is part of your security boundary.&lt;/p&gt;

&lt;p&gt;Practical checks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Inspect what your package will publish&lt;/span&gt;
npm pack &lt;span class="nt"&gt;--dry-run&lt;/span&gt;

&lt;span class="c"&gt;# Search for source maps&lt;/span&gt;
find dist &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.map"&lt;/span&gt;

&lt;span class="c"&gt;# Search for environment files&lt;/span&gt;
find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;".env*"&lt;/span&gt; &lt;span class="nt"&gt;-not&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt; &lt;span class="s2"&gt;"./node_modules/*"&lt;/span&gt;

&lt;span class="c"&gt;# Check package contents&lt;/span&gt;
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-tf&lt;/span&gt; your-package-&lt;span class="k"&gt;*&lt;/span&gt;.tgz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add CI checks to prevent accidental publication:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Package Safety Check&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;package-check&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build package&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci &amp;amp;&amp;amp; npm run build&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Block source maps in dist&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;if find dist -name "*.map" | grep .; then&lt;/span&gt;
            &lt;span class="s"&gt;echo "Source maps found in dist"&lt;/span&gt;
            &lt;span class="s"&gt;exit 1&lt;/span&gt;
          &lt;span class="s"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Prepare for autonomous agents
&lt;/h3&gt;

&lt;p&gt;AI coding tools are moving toward background operation.&lt;/p&gt;

&lt;p&gt;That means teams need workflow controls that do not depend on who made the change.&lt;/p&gt;

&lt;p&gt;For API teams, require every pull request to validate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; OpenAPI schema
&lt;span class="p"&gt;-&lt;/span&gt; API contract tests
&lt;span class="p"&gt;-&lt;/span&gt; Backward compatibility
&lt;span class="p"&gt;-&lt;/span&gt; Generated SDK changes
&lt;span class="p"&gt;-&lt;/span&gt; Documentation updates
&lt;span class="p"&gt;-&lt;/span&gt; Mock server behavior
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A useful pull request checklist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## API change checklist&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; [ ] OpenAPI spec updated
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Contract tests updated
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Mock responses updated
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Docs updated
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Breaking changes documented
&lt;span class="p"&gt;-&lt;/span&gt; [ ] AI-generated changes disclosed, if applicable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Decide how much transparency you require
&lt;/h3&gt;

&lt;p&gt;The leak revealed internal behavior that users generally could not inspect beforehand.&lt;/p&gt;

&lt;p&gt;That does not automatically mean the tool is unsafe. But it does show the trade-off between proprietary tools and inspectable tools.&lt;/p&gt;

&lt;p&gt;When evaluating AI coding tools, ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; Can we inspect how the tool handles code and prompts?
&lt;span class="p"&gt;-&lt;/span&gt; Is there a public security model?
&lt;span class="p"&gt;-&lt;/span&gt; Are data retention rules documented?
&lt;span class="p"&gt;-&lt;/span&gt; Can we disable telemetry?
&lt;span class="p"&gt;-&lt;/span&gt; Can we restrict repository access?
&lt;span class="p"&gt;-&lt;/span&gt; Can we enforce AI disclosure?
&lt;span class="p"&gt;-&lt;/span&gt; Can we audit actions taken by the tool?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is Claude Code safe to use after the source leak?
&lt;/h3&gt;

&lt;p&gt;The leak exposed source code, not user data. Anthropic removed the &lt;code&gt;.map&lt;/code&gt; file, and the source is no longer distributed with the npm package.&lt;/p&gt;

&lt;p&gt;The revealed features, including anti-distillation, frustration detection, undercover mode, and client attestation, are architectural decisions rather than direct evidence of leaked user data.&lt;/p&gt;

&lt;p&gt;Whether you are comfortable with those decisions is a separate trust and governance question.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is undercover mode in Claude Code?
&lt;/h3&gt;

&lt;p&gt;Undercover mode prevents Claude Code from revealing internal Anthropic project names, codenames, and its own identity when operating in non-Anthropic repositories.&lt;/p&gt;

&lt;p&gt;It activates automatically and cannot be disabled. The practical effect is that AI-generated contributions may not identify themselves as written with Claude Code.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are fake tools in Claude Code?
&lt;/h3&gt;

&lt;p&gt;Fake tools are decoy tool definitions injected into the system prompt when anti-distillation is enabled.&lt;/p&gt;

&lt;p&gt;They do not represent real capabilities. Their purpose is to poison captured training data so competitors recording API traffic cannot cleanly reproduce Claude’s tool-use behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is KAIROS in Claude Code?
&lt;/h3&gt;

&lt;p&gt;KAIROS is an unreleased, feature-flagged autonomous agent mode found in the leaked Claude Code source.&lt;/p&gt;

&lt;p&gt;The scaffolding included background daemon workers, GitHub webhook subscriptions, daily logging, and a &lt;code&gt;/dream&lt;/code&gt; skill for memory distillation.&lt;/p&gt;

&lt;p&gt;It suggests Anthropic has been building an always-on coding agent that can monitor repositories and act autonomously.&lt;/p&gt;

&lt;h3&gt;
  
  
  How did the Claude Code source code leak?
&lt;/h3&gt;

&lt;p&gt;A Bun runtime bug caused source maps to be included in production builds when they should not have been.&lt;/p&gt;

&lt;p&gt;Because Claude Code used Bun in its build pipeline, the &lt;code&gt;.map&lt;/code&gt; file was shipped with the npm package. Anyone inspecting the package could read the complete unminified source.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does this leak affect Claude API users?
&lt;/h3&gt;

&lt;p&gt;The leak exposed the Claude Code CLI source, not the Claude API itself.&lt;/p&gt;

&lt;p&gt;API keys, user data, and model weights were not part of the reported leak. Claude API users could continue using the API normally.&lt;/p&gt;

&lt;p&gt;The anti-distillation mechanisms discussed here are specific to Claude Code’s request pipeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I worry about frustration detection in AI coding tools?
&lt;/h3&gt;

&lt;p&gt;That depends on your privacy and telemetry requirements.&lt;/p&gt;

&lt;p&gt;Claude Code used regex patterns to detect frustration signals such as profanity or emotional language. This is faster and cheaper than running an LLM-based sentiment classifier on every prompt.&lt;/p&gt;

&lt;p&gt;The practical step is to check whether your AI tools document prompt telemetry and whether your organization can disable or govern it.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does this relate to the Axios npm attack on the same day?
&lt;/h3&gt;

&lt;p&gt;Both events occurred on March 31, 2026, but they were unrelated.&lt;/p&gt;

&lt;p&gt;The Axios incident was a deliberate supply-chain compromise through npm account hijacking. The Claude Code leak was an accidental build/package issue.&lt;/p&gt;

&lt;p&gt;Together, they increased scrutiny of npm package security and the trust developers place in distributed tooling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Claude Code’s source leaked because a Bun build issue shipped source maps in the npm package.&lt;/li&gt;
&lt;li&gt;Anti-distillation mechanisms used fake tools and summarized connector text to make model copying harder.&lt;/li&gt;
&lt;li&gt;Undercover mode prevented Claude Code from revealing internal Anthropic names and its own identity in non-Anthropic repositories.&lt;/li&gt;
&lt;li&gt;Frustration detection used regex patterns on user prompts.&lt;/li&gt;
&lt;li&gt;KAIROS scaffolding revealed an unreleased autonomous background agent mode.&lt;/li&gt;
&lt;li&gt;Client attestation cryptographically verified requests from legitimate Claude Code binaries.&lt;/li&gt;
&lt;li&gt;Shell execution security received significant hardening, including 23 numbered checks.&lt;/li&gt;
&lt;li&gt;API teams should enforce contract tests, documentation updates, and disclosure policies regardless of whether changes come from humans or AI agents.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI coding tools are now part of your development and security surface. Treat them like any other privileged tool: inspect what you can, constrain what you cannot, and build API workflows that stay consistent when humans or agents make changes.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
