feat(cli): deprecate rules command in favor of skills#1361
Open
stefanjudis wants to merge 3 commits into
Open
Conversation
The rules command read the bundled checkly.rules.md and wrote it into AI IDE config folders. That capability now lives in `checkly skills`, so rules is reduced to a deprecation notice pointing users there.
The rules command no longer reads checkly.rules.md, so drop its generation from the AI-context pipeline along with the now-dead heading helpers, and remove the step that attached it to GitHub Releases. The finalize-release job keeps marking the release as latest.
stefanjudis
commented
Jun 25, 2026
| permissions: | ||
| contents: write | ||
| steps: | ||
| - name: Download LLM rules artifact |
Collaborator
Author
There was a problem hiding this comment.
This part is here to make the rules accessible on the docs via a marketing site redirect. I'll clean that all up.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR deprecates the legacy checkly rules CLI command (which previously generated AI IDE “rules” files) in favor of the newer checkly skills flow, and removes the now-dead checkly.rules.md generation/release plumbing from the AI-context pipeline and release workflow.
Changes:
- Replace
checkly rulesbehavior with a deprecation notice and mark the command as deprecated in oclif metadata. - Update the AI-context build script to stop generating
checkly.rules.mdand simplify related helpers. - Remove the release-workflow step that uploaded
checkly.rules.md, and update release documentation accordingly.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/cli/src/commands/rules.ts | Removes rules-file generation logic and turns the command into a deprecation stub. |
| packages/cli/src/commands/tests/rules.spec.ts | Adds a unit test asserting the deprecation message output. |
| packages/cli/scripts/prepare-ai-context.ts | Stops generating checkly.rules.md; renames output-dir constant; keeps onboarding assets copy. |
| CONTRIBUTING.md | Updates release instructions to reflect that rules asset is no longer attached. |
| .github/workflows/release.yml | Removes the step that downloaded/uploaded checkly.rules.md and keeps “mark latest” logic. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
8
to
+12
| static description = | ||
| 'Generate a rules file to use with AI IDEs and Copilots.' | ||
|
|
||
| async run (): Promise<void> { | ||
| // Read the base rules file | ||
| const rulesContent = await this.readBaseRulesFile() | ||
| if (!rulesContent) { | ||
| this.error(`Failed to read rules file at ${BASE_RULES_FILE_PATH}`) | ||
| } | ||
|
|
||
| // In non-interactive mode, print rules to stdout and exit | ||
| const isNonInteractive = !process.stdin.isTTY | ||
| || !process.stdout.isTTY | ||
| || process.env.CI | ||
| || process.env.CHECKLY_NON_INTERACTIVE | ||
| if (isNonInteractive) { | ||
| this.log(rulesContent) | ||
| return | ||
| } | ||
|
|
||
| try { | ||
| // Create options for multiselect - offer all configs from AI_IDE_CONFIGS | ||
| const choices = Object.entries(AI_IDE_CONFIGS).map(([ideName, ideConfig]) => { | ||
| return { | ||
| title: `${ideName} (${path.join(ideConfig.rulesFolder, ideConfig.rulesFileName)})`, | ||
| value: ideConfig, | ||
| selected: false, | ||
| } | ||
| }) | ||
|
|
||
| const isNonInteractive = !process.stdin.isTTY | ||
| || !process.stdout.isTTY | ||
| || process.env.CI | ||
| || process.env.CHECKLY_NON_INTERACTIVE | ||
|
|
||
| // Interactive mode - show multiselect | ||
| const { configs: selectedConfig } = await prompts({ | ||
| type: 'select', | ||
| name: 'configs', | ||
| message: 'Select the AI IDE configurations to generate rules for:', | ||
| choices, | ||
| initial: 0, | ||
| }) | ||
|
|
||
| if (!selectedConfig) { | ||
| this.log('Operation cancelled.') | ||
| return | ||
| } | ||
|
|
||
| this.log(`Generating rules`) | ||
|
|
||
| // Create rules directory if it doesn't exist | ||
| const rulesDir = join(process.cwd(), selectedConfig.rulesFolder) | ||
| try { | ||
| await mkdir(rulesDir, { recursive: true }) | ||
| } catch { | ||
| // Directory might already exist, ignore error | ||
| } | ||
|
|
||
| // Determine the target file path | ||
| const rulesFilePath = join(rulesDir, selectedConfig.rulesFileName) | ||
|
|
||
| // Check if file already exists and ask for confirmation (only in interactive mode) | ||
| let shouldOverwrite = true | ||
| if (!isNonInteractive) { | ||
| shouldOverwrite = await this.confirmOverwrite(rulesFilePath) | ||
| } | ||
|
|
||
| if (!shouldOverwrite) { | ||
| this.log(`Skipped ${rulesFilePath}`) | ||
| return | ||
| } | ||
|
|
||
| // Save the rules file | ||
| await writeFile(rulesFilePath, rulesContent, 'utf8') | ||
|
|
||
| this.log(`✅ Successfully saved Checkly rules file to: ${rulesFilePath}`) | ||
| } catch (error) { | ||
| this.error(`Failed to generate rules file: ${error}`) | ||
| } | ||
| } | ||
|
|
||
| private async readBaseRulesFile (): Promise<string> { | ||
| try { | ||
| return await readFile(BASE_RULES_FILE_PATH, 'utf8') | ||
| } catch (error) { | ||
| throw new Error( | ||
| `Failed to read base rules file at ${BASE_RULES_FILE_PATH}: ${error}`, | ||
| { cause: error }, | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| private async confirmOverwrite (targetPath: string): Promise<boolean> { | ||
| try { | ||
| await access(targetPath, constants.F_OK) | ||
|
|
||
| // File exists, ask for confirmation | ||
| const { overwrite } = await prompts({ | ||
| type: 'confirm', | ||
| name: 'overwrite', | ||
| message: `Rules file already exists at ${targetPath}. Do you want to overwrite it?`, | ||
| initial: false, | ||
| }) | ||
| 'Deprecated. Use `checkly skills` instead.' | ||
|
|
||
| return overwrite ?? false | ||
| } catch { | ||
| // File doesn't exist, no need to confirm | ||
| return true | ||
| } | ||
| run (): Promise<void> { | ||
| this.log('Rules were deprecated. Use `npx checkly skills`.') |
Comment on lines
+27
to
+29
| const logged = getLogged(cmd) | ||
| expect(logged.some(m => m.includes('Rules were deprecated.'))).toBe(true) | ||
| expect(logged.some(m => m.includes('npx checkly skills'))).toBe(true) |
Comment on lines
+108
to
109
| 1. Publish a Github Release with a valid tag `#.#.#` (do **not** include a `v` prefix) and click the `Generate release notes` button to auto-generate notes following format defined [here](https://github.com/checkly/checkly-cli/blob/main/.github/release.yml). **Uncheck "Set as the latest release"** — the workflow will mark it as latest automatically. | ||
| 2. When release is published the Github action is triggered. It builds and publishes `#.#.#-prerelease` prereleases (for both packages). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Affected Components
Notes for the Reviewer
Deprecates the
checkly rulescommand and removes the AI-context artifact it depended on.Command (
src/commands/rules.ts) — previously read the bundleddist/ai-context/checkly.rules.mdand wrote it into AI IDE config folders(
.cursor/rules,.windsurf/rules,.github/instructions, etc.). Thatcapability now lives in
checkly skills, so the command is reduced to adeprecation notice:
readOnly/idempotentmetadata and is markedstatic state = 'deprecated', so oclif also surfaces a deprecation warning.AI-context pipeline (
scripts/prepare-ai-context.ts) — stops generatingcheckly.rules.mdand drops the now-dead heading/frontmatter helpers. Renamedthe misleading
RULES_OUTPUT_DIRconstant (it only feeds onboarding output now).Release workflow (
release.yml) — removes the step that attachedcheckly.rules.mdto GitHub Releases; thefinalize-releasejob still marksthe release as latest. Updated
CONTRIBUTING.mdaccordingly.Left in place / for reviewer's call: the
releasejob'sSave LLM rules as an artifactstep (uploads the wholedist/ai-context/*bundle as
llm-rules-release) is now orphaned — its only consumer was thefinalize download. I kept it since it archives the full AI-context bundle, not
just rules, and its prerelease twin was already unconsumed. Happy to drop it if
we'd rather not keep dead archival.
New Dependency Submission
None.