Skip to content

Capture app context (api_key/project_type) in analytics for every command#7771

Draft
nelsonwittwer wants to merge 2 commits into
mainfrom
telemetry-app-context-everywhere
Draft

Capture app context (api_key/project_type) in analytics for every command#7771
nelsonwittwer wants to merge 2 commits into
mainfrom
telemetry-app-context-everywhere

Conversation

@nelsonwittwer

@nelsonwittwer nelsonwittwer commented Jun 9, 2026

Copy link
Copy Markdown

What

Makes command analytics opportunistically capture app context — every CLI command, not just commands that load an app.

Why

App-level telemetry is already flowing, but only as a side effect of commands that authenticate and load an app

Commands that don't load an app (search, fetch-doc, version, upgrade, …) emit nothing, so we can't tell what app context they were run in. We need this signal everywhere so we can judge effectiveness of commands, especially by agents in different harnesses/models.

How

The public_command_metadata hook runs on the postrun of every command. It now calls a best-effort helper, logAppContextMetadataIfAuthenticated(cwd()), which — only when the user is already authenticated and is inside an app project — reads the app from disk and attaches metadata.

It is strictly best-effort and safe to run everywhere:

  • Gated on an existing local session (sessionExists()) — never triggers a login, never makes a network request. Anonymous/CI usage stays unenriched.
  • Short-circuits when api_key is already set — app commands already populated it, so there's no redundant work.
  • Never promptsskipPrompts is threaded through localAppContextgetAppConfigurationContext.
  • Bounded by a 3s timeout — it runs before process exit, so it can't hang the CLI.
  • Swallows all errors — not an app dir, invalid config, etc. → silently does nothing.

…mand

Today only commands that load an app (app dev/deploy/...) populate api_key and
project_type in Monorail; lightweight commands (search, fetch-doc, version, ...)
emit nothing, so there's no way to know what app context they ran in.

Enrich the global public_command_metadata hook so that — for users who are ALREADY
authenticated and inside an app project — it reads the app from disk and attaches
api_key + project_type. It is strictly best-effort:
- gated on an existing local session; never triggers a login or any network call
- short-circuits when api_key is already set (an app command already loaded the app)
- threads skipPrompts through localAppContext so it can never prompt
- bounded by a 3s timeout so it can't delay command exit
- swallows all errors (not an app dir, invalid config, etc.)

Adds a passive, non-interactive `sessionExists()` to @shopify/cli-kit/node/session.
No Monorail schema change: api_key/project_type already exist on the event.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the Area: @shopify/cli @shopify/cli package issues label Jun 9, 2026
Comment thread packages/app/src/cli/hooks/public_metadata.ts Outdated
Comment thread packages/app/src/cli/services/app-context.ts
Comment thread packages/app/src/cli/services/app-context.ts Outdated
Comment thread packages/app/src/cli/services/app-context.ts Outdated
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

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

We found no new type declarations in this PR

Existing type declarations

packages/cli-kit/dist/public/node/session.d.ts
@@ -47,6 +47,22 @@ export declare function isUserAccount(account: AccountInfo): account is UserAcco
  * @returns True if the account is a ServiceAccount.
  */
 export declare function isServiceAccount(account: AccountInfo): account is ServiceAccountInfo;
+/**
+ * Reports whether the CLI already has stored credentials, without prompting the
+ * user, opening a browser, or making any network request.
+ *
+ * This is a passive, side-effect-free check: it reads the local session store and
+ * returns  when at least one valid session is present. Unlike the
+ *  functions, it never triggers a login flow and never logs
+ * the user out. Because it does not contact the network, it cannot tell whether the
+ * stored token is currently valid/unexpired — only that credentials exist locally.
+ *
+ * Intended for best-effort, opportunistic behaviour (for example, enriching
+ * telemetry only for users who are already logged in).
+ *
+ * @returns True if local credentials exist, false otherwise.
+ */
+export declare function sessionExists(): Promise<boolean>;
 /**
  * Ensure that we have a valid session with no particular scopes.
  *

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

Labels

Area: @shopify/cli @shopify/cli package issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant