Workflow for splitting an existing SettingRegistration into a SettingDescriptor (placed in the lowest layer where used: core/, models/, or ui/settings/) and SettingUIDescriptor (registered in a higher-level -meta.ts file, outside of core/ and models/).
64
76%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./.agents/skills/devtools-setting-migration/SKILL.mdThis skill guide describes how to migrate an existing legacy SettingRegistration in DevTools by splitting it into a SettingDescriptor (non-UI descriptor) and a SettingUIDescriptor (UI descriptor).
SettingDescriptor Location ("Lowest Layer")SettingDescriptor MUST be placed in the lowest architectural layer where the setting is used.
core/sdk (or models/), its SettingDescriptor should be located in core/sdk (or models/).panels/console/), its SettingDescriptor MUST GO INTO ui/settings/FooSettings.ts (e.g. ui/settings/ConsoleSettings.ts where Foo is the panel name).panels/:
SettingDescriptor MUST NOT be placed inside a panels/ directory (e.g. panels/console/ConsoleSettings.ts).-meta.ts files (e.g. panels/console/console-meta.ts) need to import the SettingDescriptor to call SettingsUI.SettingUIRegistration.register(descriptor, uiDescriptor). -meta.ts files are loaded early and MUST NOT import from panels/ (which would break lazy-loading of panel bundles). Since ui/settings/ is in the ui/ layer below panels/, -meta.ts files can safely import from ui/settings/.-meta.ts FILE:
SettingDescriptor MUST NOT be placed in a -meta.ts file.Settings.instance().resolve(descriptor). Preload -meta.ts files are meant for lazy-loaded extension registrations and must not be imported by runtime code to avoid circular dependencies and module boundary violations.SettingUIDescriptor Location (Higher-Level -meta.ts File)SettingUIDescriptor defines UI-specific properties (category, title, tags, options, reload requirement, etc.).-meta.ts FILE ON A HIGHER LEVEL (e.g., entrypoints/main/main-meta.ts, entrypoints/inspector_main/inspector_main-meta.ts, panels/settings/settings-meta.ts, or the specific panel's -meta.ts file).core/ OR models/:
-meta.ts files under core/ or models/ (such as core/sdk/sdk-meta.ts or models/*/*-meta.ts).-meta.ts files in core/ and models/.moduleSetting(name)Settings.instance().moduleSetting('setting-name').moduleSetting('setting-name') with Settings.instance().resolve(settingDescriptor).Given a setting name (e.g., 'preserve-console-log' or 'network-messages'):
-meta.ts files to find its Common.Settings.registerSettingExtension block.'setting-name' or moduleSetting('setting-name') across the codebase to identify all use-sites.core/sdk -> Target directory is core/sdk/.models/ -> Target directory is models/<module>/.panels/foo) or UI -> Target directory is ui/settings/ (file: ui/settings/FooSettings.ts). NEVER place descriptors in panels/.SettingDescriptor in the Lowest LayerWhen placing a SettingDescriptor in the target directory, decide whether to create or update a file using these rules:
For Panel / UI Settings (Target is ui/settings/):
ui/settings/FooSettings.ts already exists (e.g., ui/settings/ConsoleSettings.ts). If so, add and export the SettingDescriptor there.ui/settings/FooSettings.ts does not exist:
ui/settings/FooSettings.ts.FooSettings.ts to sources in ui/settings/BUILD.gn.FooSettings.ts from ui/settings/settings.ts.For Core / Model Settings (Target is core/ or models/):
core/sdk/SDKSettings.ts, models/workspace/WorkspaceSettings.ts). If so, add and export the SettingDescriptor there.ResourceTreeModel.ts), update that .ts file by exporting the SettingDescriptor at the top.<Module>Settings.ts (e.g., core/sdk/SDKSettings.ts), add it to sources in BUILD.gn, and export it from the module's entrypoint (sdk.ts).Define and export the SettingDescriptor in the target file:
import type * as Common from '../core/common/common.js';
export const preserveConsoleLogSettingDescriptor: Common.Settings.SettingDescriptor<boolean> = {
name: 'preserve-console-log',
type: Common.Settings.SettingType.BOOLEAN,
defaultValue: false,
storageType: Common.Settings.SettingStorageType.SYNCED,
};Note: For conditional settings (dependent on hostConfig), use Common.Settings.ConditionalSettingDescriptor<ValueT, ReasonT> with an isAvailable function.
-meta.ts FileIf the original registration was in a core/ or models/ -meta.ts file (e.g., core/sdk/sdk-meta.ts), MOVE the UI registration to a higher-level -meta.ts file (e.g., entrypoints/main/main-meta.ts or panels/console/console-meta.ts).
In the higher-level -meta.ts file:
SettingsUI from ui/settings/settings.js (e.g., import * as SettingsUI from '../../ui/settings/settings.js';).SettingDescriptor (from core/sdk/, models/, or ui/settings/).SettingsUI.SettingUIRegistration.register(...):import * as SettingsUI from '../../ui/settings/settings.js';
import * as SDK from '../../core/sdk/sdk.js';
SettingsUI.SettingUIRegistration.register(SDK.SDKSettings.preserveConsoleLogSettingDescriptor, {
category: Common.Settings.SettingCategory.CONSOLE,
title: i18nLazyString(UIStrings.preserveLogUponNavigation),
options: [
{
value: true,
title: i18nLazyString(UIStrings.preserveLogUponNavigation),
},
{
value: false,
title: i18nLazyString(UIStrings.doNotPreserveLogUponNavigation),
},
],
});Common.Settings.registerSettingExtension call from the core/ or models/ -meta.ts file. (If the -meta.ts file becomes empty, delete the file and clean up its build references).moduleSetting to resolve)Find all call sites referencing the setting via moduleSetting:
// BEFORE:
const setting = Common.Settings.Settings.instance().moduleSetting('preserve-console-log');
// AFTER:
import { preserveConsoleLogSettingDescriptor } from './SDKSettings.js';
...
const setting = Common.Settings.Settings.instance().resolve(preserveConsoleLogSettingDescriptor);For conditional settings, use Common.Settings.Settings.instance().maybeResolve(descriptor) instead of resolve(descriptor).
BUILD.gn Files and Module Entrypoints.ts file was created (e.g., SDKSettings.ts or ui/settings/ConsoleSettings.ts):
sources in its module's BUILD.gn.sdk.ts, settings.ts, etc.).core/ or models/ -meta.ts file was deleted, remove it from BUILD.gn and devtools_grd_files.gni.devtools-imports skill).autoninja -C out/Default to check GN build.npm run lint to check style and formatting rules.preserve-console-log)Setting registered in front_end/core/sdk/sdk-meta.ts (Legacy core meta file):
Common.Settings.registerSettingExtension({
category: Common.Settings.SettingCategory.CONSOLE,
storageType: Common.Settings.SettingStorageType.SYNCED,
title: i18nLazyString(UIStrings.preserveLogUponNavigation),
settingName: 'preserve-console-log',
settingType: Common.Settings.SettingType.BOOLEAN,
defaultValue: false,
options: [...],
});Setting used in front_end/core/sdk/ResourceTreeModel.ts:
const setting = Common.Settings.Settings.instance().moduleSetting('preserve-console-log');front_end/core/sdk/SDKSettings.ts (Lowest Layer in Core — NOT a -meta.ts file):import type * as Common from '../common/common.js';
export const preserveConsoleLogSettingDescriptor: Common.Settings.SettingDescriptor<boolean> = {
name: 'preserve-console-log',
type: Common.Settings.SettingType.BOOLEAN,
defaultValue: false,
storageType: Common.Settings.SettingStorageType.SYNCED,
};front_end/entrypoints/main/main-meta.ts (Higher-Level Meta File — NOT in core/ or models/):import * as SDK from '../../core/sdk/sdk.js';
import * as SettingsUI from '../../ui/settings/settings.js';
SettingsUI.SettingUIRegistration.register(SDK.SDKSettings.preserveConsoleLogSettingDescriptor, {
category: Common.Settings.SettingCategory.CONSOLE,
title: i18nLazyString(UIStrings.preserveLogUponNavigation),
options: [...],
});front_end/core/sdk/ResourceTreeModel.ts (Call Site in core/sdk):import { preserveConsoleLogSettingDescriptor } from './SDKSettings.js';
const setting = Common.Settings.Settings.instance().resolve(preserveConsoleLogSettingDescriptor);front_end/core/sdk/sdk-meta.ts:
Registration for 'preserve-console-log' removed.network-messages)Setting registered in front_end/panels/console/console-meta.ts:
Common.Settings.registerSettingExtension({
category: Common.Settings.SettingCategory.CONSOLE,
storageType: Common.Settings.SettingStorageType.SYNCED,
title: i18nLazyString(UIStrings.networkMessages),
settingName: 'network-messages',
settingType: Common.Settings.SettingType.BOOLEAN,
defaultValue: true,
options: [...],
});Setting used in front_end/panels/console/ConsoleView.ts:
const setting = Common.Settings.Settings.instance().moduleSetting('network-messages');front_end/ui/settings/ConsoleSettings.ts (Lowest Layer for UI/Panel Descriptor — NOT in panels/console/!):import type * as Common from '../../core/common/common.js';
export const networkMessagesSettingDescriptor: Common.Settings.SettingDescriptor<boolean> = {
name: 'network-messages',
type: Common.Settings.SettingType.BOOLEAN,
defaultValue: true,
storageType: Common.Settings.SettingStorageType.SYNCED,
};front_end/panels/console/console-meta.ts (Panel Meta File — Imports Descriptor from ui/settings/):import * as SettingsUI from '../../ui/settings/settings.js';
SettingsUI.SettingUIRegistration.register(SettingsUI.ConsoleSettings.networkMessagesSettingDescriptor, {
category: Common.Settings.SettingCategory.CONSOLE,
title: i18nLazyString(UIStrings.networkMessages),
options: [...],
});front_end/panels/console/ConsoleView.ts (Call Site in panels/console):import * as SettingsUI from '../../ui/settings/settings.js';
const setting = Common.Settings.Settings.instance().resolve(SettingsUI.ConsoleSettings.networkMessagesSettingDescriptor);SettingDescriptor<T>Defined in core/common/Settings.ts:
name: string: Unique setting name (kebab-case).type: SettingType: BOOLEAN, ENUM, ARRAY, or REGEX.defaultValue: ValueT | ((hostConfig: HostConfig) => ValueT): Default setting value.storageType?: SettingStorageType: SYNCED, LOCAL, GLOBAL, or SESSION.SettingUIDescriptorDefined in ui/settings/SettingUIRegistration.ts:
category?: SettingCategory: Category under which setting is listed in Settings UI.order?: number: Sorting order.title?: () => LocalizedString: Title string displayed in Settings UI.tags?: Array<() => LocalizedString>: Search tags for Command Menu.options?: SettingExtensionOption[]: Enum / boolean option descriptions.reloadRequired?: boolean: Whether setting change requires DevTools reload.deprecationNotice?: { disabled: boolean, warning: () => LocalizedString, experiment?: string }: Deprecation notice.learnMore?: LearnMore: Help link or tooltip info.184a74d
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.