Skip to content

Add CLI docs search and GraphQL validation#7690

Draft
dmerand wants to merge 1 commit into
donald/agent-session-pocfrom
donald/agent-session-docs-validate-poc
Draft

Add CLI docs search and GraphQL validation#7690
dmerand wants to merge 1 commit into
donald/agent-session-pocfrom
donald/agent-session-docs-validate-poc

Conversation

@dmerand
Copy link
Copy Markdown
Contributor

@dmerand dmerand commented Jun 1, 2026

What

Adds a proof-of-concept CLI-owned docs search and GraphQL validation path for agent workflows, stacked on top of the agent session prototype.

This PR adds:

  • shopify docs search <query> --api <api-name> --json
  • shopify validate graphql --query/--query-file ... --schema-file ... --variables/--variable-file ... --json
  • CLI command registration for docs:search and validate:graphql
  • a direct graphql dependency for the CLI package

Why

The base PR proves CLI-owned agent session state. This upstack PR proves the next deterministic agent steps can also move into the CLI:

  1. start one agent session
  2. search Shopify.dev docs through CLI
  3. validate generated GraphQL through CLI
  4. execute through existing shopify store execute

The goal is a reference-quality PoC for reducing repeated ai-toolkit-source script glue while keeping Shopify.dev as the docs/source-of-truth surface.

Behavior

Docs search

shopify docs search uses the same Shopify.dev assistant endpoint used by generated ai-toolkit skills:

POST /assistant/search

Request body:

{
  "query": "...",
  "api_name": "admin"
}

The CLI service preserves ai-toolkit's Shopify.dev host routing behavior:

  • default: https://shopify.dev/
  • DEV=true: https://shopify-dev.shop.dev/
  • SHOPIFY_DEV_STAGING_SERVER_NUMBER + MINERVA_TOKEN: staging host

It sends X-Shopify-Surface: cli so this path is attributable as CLI-owned rather than skill-owned.

GraphQL validation

shopify validate graphql currently validates:

  • GraphQL syntax
  • exactly one operation
  • operation type/name
  • variables JSON parsing
  • schema validation when --schema-file is provided
  • variable coercion against the provided schema

Schema files can be either:

  • SDL .graphql
  • introspection JSON

Invalid validation results print structured JSON and exit non-zero via AbortSilentError.

Example invalid result:

{
  "valid": false,
  "issues": [
    {
      "message": "Cannot query field ...",
      "stage": "schema",
      "locations": [{"line": 1, "column": 9}]
    }
  ],
  "operation": {"type": "query"},
  "schema": {"source": "file", "validation": "checked"}
}

Demo flow

shopify agent session start \
  --agent pi \
  --agent-version 0.77.0 \
  --provider shopify \
  --metrics on \
  --default-non-interactive \
  --json

shopify docs search \
  "inventorySetQuantities required scopes" \
  --api admin \
  --json

shopify validate graphql \
  --query-file ./mutation.graphql \
  --schema-file ./admin.schema.graphql \
  --variables-file ./variables.json \
  --json

shopify store execute \
  --store example.myshopify.com \
  --query-file ./mutation.graphql \
  --variables-file ./variables.json \
  --allow-mutations \
  --json

Boundaries

This PR does not yet:

  • auto-fetch or bundle Admin schemas via --surface admin
  • infer required OAuth scopes from GraphQL validation
  • replace every ai-toolkit validator
  • make /assistant/search a public Shopify.dev API contract

Those are follow-on design decisions. This PR is intentionally a PoC, but it is structured as a realistic reference implementation rather than a placeholder.

Testing

pnpm vitest run \
  packages/cli/src/cli/services/docs/search.test.ts \
  packages/cli/src/cli/commands/docs/search.test.ts \
  packages/cli/src/cli/services/validation/graphql.test.ts \
  packages/cli/src/cli/commands/validate/graphql.test.ts \
  packages/cli/src/cli/commands/agent/session/start.test.ts \
  packages/app/src/cli/commands/app/release.test.ts

pnpm --filter @shopify/cli lint
pnpm --filter @shopify/cli type-check
pnpm --filter @shopify/cli build

@github-actions github-actions Bot added the no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users. label Jun 1, 2026
@dmerand dmerand force-pushed the donald/agent-session-poc branch from 5387c2e to 8a8489a Compare June 1, 2026 19:16
@dmerand dmerand force-pushed the donald/agent-session-docs-validate-poc branch from 4324549 to 79e2fca Compare June 1, 2026 19:17
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 1, 2026

Differences in type declarations

We detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:

  • Some seemingly private modules might be re-exported through public modules.
  • If the branch is behind main you might see odd diffs, rebase main into this branch.

New type declarations

packages/cli-kit/dist/public/node/agent.d.ts
import { LocalStorage } from './local-storage.js';
import { AgentSession, ConfSchema } from '../../private/node/conf-store.js';
export type { AgentSession };
export interface StartAgentSessionOptions {
    sessionId: string;
    agentName: string;
    agentVersion: string;
    agentProvider: string;
    metricsMode?: 'on' | 'off';
    defaultNonInteractive?: boolean;
}
/**
 * Start a new agent session.
 *
 * Persists the agent session state to the CLI kit config store.
 *
 * @param options - Agent session configuration.
 * @param config - Optional config store for testing.
 * @returns The persisted session value.
 */
export declare function startAgentSession(options: StartAgentSessionOptions, config?: LocalStorage<ConfSchema>): AgentSession;
/**
 * Get the current agent session.
 *
 * @param config - Optional config store for testing.
 * @returns Current agent session, or undefined if no session is active.
 */
export declare function getCurrentAgentSession(config?: LocalStorage<ConfSchema>): AgentSession | undefined;
/**
 * Clear the current agent session.
 *
 * Removes the persisted agent session state from the CLI kit config store.
 *
 * @param config - Optional config store for testing.
 */
export declare function clearAgentSession(config?: LocalStorage<ConfSchema>): void;
/**
 * Pack SHOPIFY_CLI_AGENT_INFO environment variable value from agent session.
 *
 * The format is a tagged string with agent metadata:
 * n:<name>|v:<version>|p:<provider>.
 *
 * Precedence: explicit process.env.SHOPIFY_CLI_AGENT_INFO takes priority over
 * persisted session state.
 *
 * @param session - Optional session to pack from. If not provided, uses current session.
 * @param config - Optional config store for testing.
 * @returns Tagged string for SHOPIFY_CLI_AGENT_INFO, or undefined if no data available.
 */
export declare function packAgentInfo(session?: AgentSession, config?: LocalStorage<ConfSchema>): string | undefined;
/**
 * Pack SHOPIFY_CLI_AGENT_IDS environment variable value from agent session.
 *
 * The format is a tagged string with session identifier:
 * s:<sessionId>.
 *
 * Precedence: explicit process.env.SHOPIFY_CLI_AGENT_IDS takes priority over
 * persisted session state.
 *
 * @param session - Optional session to pack from. If not provided, uses current session.
 * @param config - Optional config store for testing.
 * @returns Tagged string for SHOPIFY_CLI_AGENT_IDS, or undefined if no data available.
 */
export declare function packAgentIds(session?: AgentSession, config?: LocalStorage<ConfSchema>): string | undefined;

Existing type declarations

packages/cli-kit/dist/private/node/conf-store.d.ts
@@ -18,11 +18,22 @@ interface Cache {
     [mostRecentOccurrenceKey: MostRecentOccurrenceKey]: CacheValue<boolean>;
     [rateLimitKey: RateLimitKey]: CacheValue<number[]>;
 }
+export interface AgentSession {
+    sessionId: string;
+    startedAt: string;
+    agentName: string;
+    agentVersion: string;
+    agentProvider: string;
+    metricsMode: 'on' | 'off';
+    defaultNonInteractive: boolean;
+}
 export interface ConfSchema {
     sessionStore: string;
     currentSessionId?: string;
     devSessionStore?: string;
     currentDevSessionId?: string;
+    currentAgentSession?: AgentSession;
+    devAgentSession?: AgentSession;
     cache?: Cache;
     autoUpgradeEnabled?: boolean;
 }
@@ -128,7 +139,8 @@ interface RunWithRateLimitOptions {
 export declare function runWithRateLimit(options: RunWithRateLimitOptions, config?: LocalStorage<ConfSchema>): Promise<boolean>;
 /**
  * Get auto-upgrade preference.
- * Defaults to true if the preference has never been explicitly set.
+ *
+ * Auto-upgrade is enabled by default when the preference has never been set.
  *
  * @returns Whether auto-upgrade is enabled.
  */
@@ -145,4 +157,20 @@ export declare function getConfigStoreForPartnerStatus(): LocalStorage<Record<st
 }>>;
 export declare function getCachedPartnerAccountStatus(partnersToken: string): true | null;
 export declare function setCachedPartnerAccountStatus(partnersToken: string): void;
+/**
+ * Get current agent session.
+ *
+ * @returns Current agent session.
+ */
+export declare function getAgentSession(config?: LocalStorage<ConfSchema>): AgentSession | undefined;
+/**
+ * Set current agent session.
+ *
+ * @param session - Agent session.
+ */
+export declare function setAgentSession(session: AgentSession, config?: LocalStorage<ConfSchema>): void;
+/**
+ * Remove current agent session.
+ */
+export declare function removeAgentSession(config?: LocalStorage<ConfSchema>): void;
 export {};
\ No newline at end of file
packages/cli-kit/dist/private/node/constants.d.ts
@@ -35,6 +35,7 @@ export declare const environmentVariables: {
     skipNetworkLevelRetry: string;
     maxRequestTimeForNetworkCalls: string;
     disableImportScanning: string;
+    hostedApps: string;
 };
 export declare const defaultThemeKitAccessDomain = "theme-kit-access.shopifyapps.com";
 export declare const systemEnvironmentVariables: {
packages/cli-kit/dist/public/common/version.d.ts
@@ -1 +1 @@
-export declare const CLI_KIT_VERSION = "4.1.0";
\ No newline at end of file
+export declare const CLI_KIT_VERSION = "3.94.0";
\ No newline at end of file
packages/cli-kit/dist/public/node/context/local.d.ts
@@ -25,6 +25,13 @@ export declare function isDevelopment(env?: NodeJS.ProcessEnv): boolean;
  * @returns True if SHOPIFY_FLAG_VERBOSE is truthy or the flag --verbose has been passed.
  */
 export declare function isVerbose(env?: NodeJS.ProcessEnv): boolean;
+/**
+ * Returns true if the hosted apps mode is enabled.
+ *
+ * @param env - The environment variables from the environment of the current process.
+ * @returns True if HOSTED_APPS is truthy.
+ */
+export declare function isHostedAppsMode(env?: NodeJS.ProcessEnv): boolean;
 /**
  * Returns true if the environment in which the CLI is running is either
  * a local environment (where dev is present).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog This PR doesn't include a changeset entry. Is an internal only change not relevant to end users.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant