<?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>Forem: Usman Khan</title>
    <description>The latest articles on Forem by Usman Khan (@usmankhan1).</description>
    <link>https://forem.com/usmankhan1</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3936172%2F6505a52b-7a2e-489d-91d0-4382c30dc5ef.jpg</url>
      <title>Forem: Usman Khan</title>
      <link>https://forem.com/usmankhan1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/usmankhan1"/>
    <language>en</language>
    <item>
      <title>Stop Briefing AI. Let It Interview You</title>
      <dc:creator>Usman Khan</dc:creator>
      <pubDate>Sun, 17 May 2026 11:42:07 +0000</pubDate>
      <link>https://forem.com/usmankhan1/stop-briefing-ai-let-it-interview-you-55ef</link>
      <guid>https://forem.com/usmankhan1/stop-briefing-ai-let-it-interview-you-55ef</guid>
      <description>&lt;p&gt;A classic "so close, yet so far" AI experience. Here is the scenario:&lt;/p&gt;

&lt;p&gt;You spend a long time giving the AI every detail it needs, but it still misses the mark. You end up spending more time fixing its mistakes than you would have spent doing the work yourself. Also, the result are not consistent with every new prompt for smaller task it perform well but fails in complex task.&lt;/p&gt;

&lt;p&gt;And you can't even blame the AI. You gave it everything at once and expected a magic.&lt;/p&gt;

&lt;p&gt;The Real Problem: One Big Prompt Is a Trap&lt;br&gt;
When you dump a giant prompt at AI, you feel like you've communicated well. You've written paragraphs. You've attached files. You've been thorough.&lt;/p&gt;

&lt;p&gt;But here's what's actually happening: your prompt has gaps. It always does. You don't know what you don't know. The AI fills those gaps — silently, confidently, and often incorrectly. It doesn't stop and ask. It just builds.&lt;/p&gt;

&lt;p&gt;And you won't find out until the end.&lt;/p&gt;

&lt;p&gt;That's the black-box problem. You get back something that almost matches what you imagined. Then you spend the next hour in refactor mode, wondering where it went wrong.&lt;/p&gt;

&lt;p&gt;A Better Way: Let AI Question You First&lt;br&gt;
What if instead of giving AI everything upfront, you let it ask you the right questions first?&lt;/p&gt;

&lt;p&gt;That's exactly what the Grill Me skill does.&lt;/p&gt;

&lt;p&gt;Here's how it works:&lt;/p&gt;

&lt;p&gt;You tell the AI what you want — in a short line or two. No essays, no spec docs.&lt;/p&gt;

&lt;p&gt;The AI starts questioning you. One question at a time. Sharp, targeted questions that expose the gaps in your thinking.&lt;/p&gt;

&lt;p&gt;For each question, it gives you a recommended answer with its reasoning — you just confirm, correct, or redirect.&lt;/p&gt;

&lt;p&gt;If the answer can be found by reading your codebase, it reads the codebase instead of bothering you.&lt;/p&gt;

&lt;p&gt;When every branch is resolved, you get a clean Decision Summary — and you can say: "Implement."&lt;/p&gt;

&lt;p&gt;No surprises. No refactoring. No "oh I didn't realize it would do that."&lt;/p&gt;

&lt;p&gt;What It Actually Looks Like in Practice&lt;br&gt;
Here's a real implementation session. Three Jira tickets needed implementing — a legacy compatibility layer for an NRP publish service. Instead of writing a long prompt, I just ran:&lt;/p&gt;

&lt;p&gt;/grill-me "implement XYZ-10499, XYZ-10501, XYZ-10503"&lt;/p&gt;

&lt;p&gt;The AI pulled up all three tickets, then explored the codebase before asking a single question. It came back with:&lt;/p&gt;

&lt;p&gt;"Got the full picture. The codebase has no legacy-compat mode detection yet — that's the foundational piece all three tickets depend on.&lt;/p&gt;

&lt;p&gt;Question 1: How will legacy-compat mode be detected?&lt;/p&gt;

&lt;p&gt;My recommendation: An org level config flag is more reliable than a header because it doesn't depend on callers always sending it correctly. Though a header-based override on top for testing would be useful. Which approach are you taking — header, org config, or both?"*&lt;/p&gt;

&lt;p&gt;Notice what happened there. I gave it three ticket links. It read them, explored the codebase, identified a missing foundational piece I hadn't even mentioned, and then asked one sharp question with a recommended answer.&lt;/p&gt;

&lt;p&gt;I responded in one line: xyz-legacy request header will be added by the intermediate service for all legacy calls automatically.&lt;/p&gt;

&lt;p&gt;The AI confirmed and moved to Question 2 — where to read and store the header — and again it had already looked at the codebase and suggested the exact right place, with code references.&lt;/p&gt;

&lt;p&gt;Question 2: Where should the xyx-legacy header be read and stored on the request context?&lt;/p&gt;

&lt;p&gt;Looking at the codebase, there are two existing patterns for request-level data propagation:&lt;br&gt;
. . .&lt;/p&gt;

&lt;p&gt;My recommendation: read xyx-legacy in abc.ts and store it as something like var.isLegacy= true/false, so all downstream pipes and services can branch on it without re-reading the header repeatedly.&lt;/p&gt;

&lt;p&gt;Is that the right place, or do you have a different layer in mind (e.g., a dedicated middleware, or reading it directly in each pipe)?&lt;/p&gt;

&lt;p&gt;Total 09 questions in, every design decision was locked in. No ambiguity. The overall session ran for 15mins. But I ended up with confidence. Overall task completion time was 45mins. Which includes below mentiond skills execution, which we will see in later post.&lt;/p&gt;

&lt;p&gt;Then I typed /to-prd and it generated a full PRD.&lt;br&gt;
Then /to-issues and it created vertical implementation slices.&lt;br&gt;
Then create a pr — and a pull request was live on GitHub.&lt;/p&gt;

&lt;p&gt;From Jira tickets to open PR, with zero rework.&lt;/p&gt;

&lt;p&gt;What Makes It Different&lt;br&gt;
A few things Grill Me does that a plain prompt never will:&lt;/p&gt;

&lt;p&gt;It reads your codebase before asking. If the answer already exists in your code, it won't ask you to re-explain it. In that session, it checked abc.ts, pqrs.pipe.ts, xyz.service.ts — and tailored every question to how your project actually works, not how a generic project would.&lt;/p&gt;

&lt;p&gt;It gives a recommendation first. You're not staring at an open-ended question wondering what the right answer even is. It says "here's what I'd do and why" — you just react. This is way faster than thinking from scratch.&lt;/p&gt;

&lt;p&gt;It catches things you missed. In that same session, the AI caught that the codebase had zero legacy-compat detection — before even getting to the actual ticket requirements. That's the kind of gap that bites you mid-implementation.&lt;/p&gt;

&lt;p&gt;It builds a shared record. By the end, the Decision Summary is the ground truth. No more "wait, what did we decide about the depth override?" It's all written down.&lt;/p&gt;

&lt;p&gt;When to Use It&lt;br&gt;
The best moments to reach for Grill Me:&lt;/p&gt;

&lt;p&gt;Before writing a PRD or TRD&lt;/p&gt;

&lt;p&gt;Before asking AI to implement a feature&lt;/p&gt;

&lt;p&gt;Before committing to a data modelling or API implementation&lt;/p&gt;

&lt;p&gt;When several design choices depend on each other&lt;/p&gt;

&lt;p&gt;When you want the AI to push back instead of just agree&lt;/p&gt;

&lt;p&gt;If you're about to write a long prompt — stop. Write two lines about what you want. Then type /grill-me. The questions alone will surface things about your own idea that you hadn't fully thought through.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>chatgpt</category>
      <category>llm</category>
      <category>productivity</category>
    </item>
    <item>
      <title>The anatomy of an APEX 26.1 APEXlang file</title>
      <dc:creator>Usman Khan</dc:creator>
      <pubDate>Sun, 17 May 2026 11:41:32 +0000</pubDate>
      <link>https://forem.com/usmankhan1/the-anatomy-of-an-apex-261-apexlang-file-1ocn</link>
      <guid>https://forem.com/usmankhan1/the-anatomy-of-an-apex-261-apexlang-file-1ocn</guid>
      <description>&lt;p&gt;Introduction&lt;br&gt;
If you have spent any time reviewing traditional APEX export SQL, you know the problem. The application is there, but it is buried inside hundreds of calls to internal APIs. You can version it, search it, and deploy it, but reading it fluently is hard work.&lt;/p&gt;

&lt;p&gt;To be fair, this is not the first time APEX has given us something better than one huge SQL export. Older versions of APEX could export an application using the Split into Multiple Files option, and APEX has also had a human-readable YAML export format. Those were useful, especially for review and source control, but the YAML format was read-only, and the split SQL export was fundamentally SQL export syntax.&lt;/p&gt;

&lt;p&gt;APEXlang makes that structure easier to work with. It mirrors the APEX Builder mental model in a source format that is intended to be read as APEX metadata: applications contain pages, pages contain regions and components, shared components live together, and SQL, PL/SQL, JavaScript, CSS, and HTML still appear where you would expect them.&lt;/p&gt;

&lt;p&gt;In this post, I will walk through the anatomy of an APEXlang .apx file and show how to build a mental model of an app quickly.&lt;/p&gt;

&lt;p&gt;The Folder Structure&lt;br&gt;
An APEXlang export is not one giant SQL file. It is exported as a zip file that expands into a folder structure.&lt;/p&gt;

&lt;p&gt;For the customers sample app, the tree looks like this:&lt;/p&gt;

&lt;p&gt;customers/&lt;br&gt;
|-- application.apx&lt;br&gt;
|-- page-groups.apx&lt;br&gt;
|-- pages/&lt;br&gt;
|   &lt;code&gt;-- p00001-dashboard.apx&lt;br&gt;
|&lt;/code&gt;-- p00050-customer.apx&lt;br&gt;
|-- shared-components/&lt;br&gt;
|   |-- app-computations.apx&lt;br&gt;
|   |-- app-items.apx&lt;br&gt;
|   |-- app-processes.apx&lt;br&gt;
|   |-- authentications.apx&lt;br&gt;
|   |-- authorizations.apx&lt;br&gt;
|   |-- breadcrumbs.apx&lt;br&gt;
|   |-- build-options.apx&lt;br&gt;
|   |-- classic-navigation-bar-entries.apx&lt;br&gt;
|   |-- component-settings.apx&lt;br&gt;
|   |-- legacy-data-load-definitions.apx&lt;br&gt;
|   |-- lists.apx&lt;br&gt;
|   |-- lovs.apx&lt;br&gt;
|   |-- messages.apx&lt;br&gt;
|   |-- plugins/region/APEXLANG-14855697926908483213/{custom-attributes.apx,plugin.apx}&lt;br&gt;
|   |-- shortcuts.apx&lt;br&gt;
|   |-- static-files.apx&lt;br&gt;
|   |-- report-layouts/report-layouts.apx&lt;br&gt;
|   |-- report-layouts/CUSTOMER-REPORT.rtf&lt;br&gt;
|   |-- static-files/icons/app-icon-32.png&lt;br&gt;
|   &lt;code&gt;-- themes/universal-theme/{template-option-groups.apx,theme.apx}&lt;br&gt;
|-- supporting-objects/&lt;br&gt;
|   |-- deinstall-script.sql&lt;br&gt;
|   |-- install-scripts.apx&lt;br&gt;
|   |-- install-scripts/activities.sql&lt;br&gt;
|   |-- supporting-objects.apx&lt;br&gt;
|   |-- substitutions.apx&lt;br&gt;
|   |-- upgrade-scripts.apx&lt;br&gt;
|&lt;/code&gt;-- upgrade-scripts/upgrade-eba-cust-spec-and-body.sql&lt;br&gt;
|-- deployments/default.json&lt;br&gt;
|-- .apex/apexlang.json&lt;br&gt;
`-- workspace-components/app-groups/APEX-184853421316436653.apx&lt;br&gt;
application.apx is the application-level definition. This is where you find the application name, version, authentication, authorization, navigation, theme, globalization, security settings, substitutions, JavaScript, CSS, and other global configuration.&lt;/p&gt;

&lt;p&gt;pages contains one file per page. The filenames are practical: p00001-home.apx, p00003-event-details-p3-event-name.apx, p00050-customer.apx, and so on. You can usually tell the page number and purpose before opening the file.&lt;/p&gt;

&lt;p&gt;shared-components contains the things you would expect from APEX Builder: LOVs, lists, breadcrumbs, authentications, authorizations, app items, app processes, themes, plugins, messages, build options, static files, and report layouts.&lt;/p&gt;

&lt;p&gt;supporting-objects contains installation, upgrade, substitution, and deinstallation metadata. The actual SQL scripts can live under folders such as supporting-objects/install-scripts and supporting-objects/upgrade-scripts.&lt;/p&gt;

&lt;p&gt;deployments contains deployment configuration. In the examples, default.json maps the app to an application ID.&lt;/p&gt;

&lt;p&gt;.apex contains APEXlang metadata. In the examples, .apex/apexlang.json identifies the APEXlang metadata version.&lt;/p&gt;

&lt;p&gt;This structure matters because it lets you navigate an app the same way you think about an app. That idea existed before APEXlang, but APEXlang makes the files easier to read. You can edit, validate, and import them back into APEX.&lt;/p&gt;

&lt;p&gt;What Lives in application.apx&lt;br&gt;
Open application.apx first.&lt;/p&gt;

&lt;p&gt;It starts with an app block:&lt;/p&gt;

&lt;p&gt;app TEAM-CALENDAR (&lt;br&gt;
    name: Team Calendar&lt;br&gt;
    version: 24.2.1&lt;br&gt;
    authentication {&lt;br&gt;
        publicUser: APEX_PUBLIC_USER&lt;br&gt;
        authenticationScheme: &lt;a class="mentioned-user" href="https://dev.to/apex"&gt;@apex&lt;/a&gt;$8947201266001685638&lt;br&gt;
    }&lt;br&gt;
    navigation {&lt;br&gt;
        homeUrl: f?p=&amp;amp;APP_ID.:1:&amp;amp;SESSION.&lt;br&gt;
    }&lt;br&gt;
)&lt;br&gt;
That reads much closer to a configuration file than an export script. You can scan it and answer basic questions quickly:&lt;/p&gt;

&lt;p&gt;What is this application called?&lt;/p&gt;

&lt;p&gt;What authentication scheme does it use?&lt;/p&gt;

&lt;p&gt;Is authorization configured globally?&lt;/p&gt;

&lt;p&gt;What is the home page?&lt;/p&gt;

&lt;p&gt;Which theme is current?&lt;/p&gt;

&lt;p&gt;Are there global substitutions?&lt;/p&gt;

&lt;p&gt;Is custom CSS or JavaScript included?&lt;/p&gt;

&lt;p&gt;You will also see the same APEX ideas you already know: session management, security, globalization, navigation, Progressive Web App settings, and substitutions.&lt;/p&gt;

&lt;p&gt;Read application.apx like the App Definition screen in APEX Builder. Do not try to understand every reference yet. Get the global shape first.&lt;/p&gt;

&lt;p&gt;How Pages Are Modeled&lt;br&gt;
Page files are where APEXlang becomes especially useful.&lt;/p&gt;

&lt;p&gt;A page starts with a page block:&lt;/p&gt;

&lt;p&gt;page 1 (&lt;br&gt;
    name: Home&lt;br&gt;
    alias: HOME&lt;br&gt;
    title: &amp;amp;APPLICATION_TITLE. - Home&lt;br&gt;
    appearance {&lt;br&gt;
        pageTemplate: @/standard&lt;br&gt;
    }&lt;br&gt;
)&lt;br&gt;
After that, the file is organized around page components. In the examples, pages contain:&lt;/p&gt;

&lt;p&gt;region&lt;/p&gt;

&lt;p&gt;item&lt;/p&gt;

&lt;p&gt;button&lt;/p&gt;

&lt;p&gt;dynamicAction&lt;/p&gt;

&lt;p&gt;validation&lt;/p&gt;

&lt;p&gt;computation&lt;/p&gt;

&lt;p&gt;process&lt;/p&gt;

&lt;p&gt;branch&lt;/p&gt;

&lt;p&gt;Again, this follows the APEX Builder mental model. To understand a page, scan the top-level component blocks first.&lt;/p&gt;

&lt;p&gt;Regions often contain their own nested configuration. A report region may include a source block, layout settings, template choices, columns, actions, conditions, and attributes.&lt;/p&gt;

&lt;p&gt;region APEX$1553489748373581675 (&lt;br&gt;
    name: Events Calendar&lt;br&gt;
    type: calendar&lt;br&gt;
    source {&lt;br&gt;
        location: localDatabase&lt;br&gt;
        type: sqlQuery&lt;br&gt;
        sqlQuery:&lt;br&gt;
            &lt;code&gt;&lt;/code&gt;&lt;code&gt;sql&lt;br&gt;
            select e.event_id&lt;br&gt;
            ,      e.event_name&lt;br&gt;
            from   eba_ca_events e&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;br&gt;
    }&lt;br&gt;
)&lt;br&gt;
That is the key pattern: the declarative APEX component is modeled structurally, and the executable code remains embedded in a fenced block.&lt;/p&gt;

&lt;p&gt;For form or dialog pages, I would scan in this order:&lt;/p&gt;

&lt;p&gt;Page name, alias, template, and security.&lt;/p&gt;

&lt;p&gt;Regions, especially the main form region.&lt;/p&gt;

&lt;p&gt;Items and their source/default/session state behavior.&lt;/p&gt;

&lt;p&gt;Buttons and button positions.&lt;/p&gt;

&lt;p&gt;Processes and branches.&lt;/p&gt;

&lt;p&gt;Validations and dynamic actions.&lt;/p&gt;

&lt;p&gt;You can usually tell whether a page is display-only, a report, a modal form, or a complex transactional page in a couple of minutes.&lt;/p&gt;

&lt;p&gt;Shared Components Become Readable&lt;br&gt;
Shared components are split into focused files. That is one of the biggest readability wins.&lt;/p&gt;

&lt;p&gt;For example, shared-components/lovs.apx contains lov blocks. A static LOV contains nested entry blocks. A SQL-based LOV contains a source block with the SQL query.&lt;/p&gt;

&lt;p&gt;lov APEX$14836072312031628364 (&lt;br&gt;
    name: USERNAME_FORMAT&lt;br&gt;
    source {&lt;br&gt;
        location: staticValues&lt;br&gt;
    }&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;entry APEX$14836072618328628365 (
    sequence: 1
    display: Email Address
    return: EMAIL
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;)&lt;br&gt;
Lists work the same way. shared-components/lists.apx contains list blocks, and each list contains entry blocks with labels, icons, links, current-page logic, and parent-child relationships.&lt;/p&gt;

&lt;p&gt;App processes live in shared-components/app-processes.apx. Authentication schemes live in shared-components/authentications.apx. Plugins live under shared-components/plugins, separated by plugin type and id. Themes live under shared-components/themes.&lt;/p&gt;

&lt;p&gt;This is much easier to review than a traditional SQL export because the file boundaries match the APEX Builder navigation, and the file contents are not wrapped in API calls.&lt;/p&gt;

&lt;p&gt;Understanding References&lt;br&gt;
APEXlang uses references heavily, and learning the reference style is what makes the files click.&lt;/p&gt;

&lt;p&gt;You will see &lt;a class="mentioned-user" href="https://dev.to/apex"&gt;@apex&lt;/a&gt;(... references in exported files. These are references to APEX components by generated identifier. For example, an application may point to an authentication scheme or navigation list using an &lt;a class="mentioned-user" href="https://dev.to/apex"&gt;@apex&lt;/a&gt;)... value.&lt;/p&gt;

&lt;p&gt;You will also see more readable references based on static ids and names:&lt;/p&gt;

&lt;p&gt;authentication {&lt;br&gt;
    scheme: @oracle-apex-accounts&lt;br&gt;
}&lt;br&gt;
userInterface {&lt;br&gt;
    currentTheme: @universal-theme&lt;br&gt;
}&lt;br&gt;
navigationMenu {&lt;br&gt;
    list: @navigation-menu&lt;br&gt;
}&lt;br&gt;
That matters because APEX 26.1 adds static ids across APEX components, and APEXlang uses those ids to make references more stable and readable.&lt;/p&gt;

&lt;p&gt;You will also see @/... references, especially for templates:&lt;/p&gt;

&lt;p&gt;pageTemplate: @/standard&lt;br&gt;
listTemplate: @/side-navigation-menu&lt;br&gt;
buttonTemplate: @/text-with-icon&lt;br&gt;
These are easier to read because the component is referenced by a friendly path-like name.&lt;/p&gt;

&lt;p&gt;Page item references still look like APEX page item references. SQL and PL/SQL blocks use bind variables such as :P50_ID, :APP_ID, and :APP_USER. URL targets still use familiar APEX substitution syntax, such as f?p=&amp;amp;APP_ID.:1:&amp;amp;SESSION..&lt;/p&gt;

&lt;p&gt;Named component references also appear naturally in places such as authorization checks, build option logic, template references, and links.&lt;/p&gt;

</description>
      <category>database</category>
      <category>softwaredevelopment</category>
      <category>sql</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
