Skip to content

feat(coding-tutor): restore coding-tutor plugin#7

Merged
metaphorics merged 1 commit into
mainfrom
revert-coding-tutor
Jun 7, 2026
Merged

feat(coding-tutor): restore coding-tutor plugin#7
metaphorics merged 1 commit into
mainfrom
revert-coding-tutor

Conversation

@metaphorics

@metaphorics metaphorics commented Jun 7, 2026

Copy link
Copy Markdown

User-directed restoration of the coding-tutor plugin (reverts 159cfee).

  • Plugin tree restored and verified byte-identical to upstream/main's current coding-tutor (git diff 159cfee^ upstream/main -- plugins/coding-tutor is empty; both at v1.3.0) — reverting the local removal and importing from upstream are the same change.
  • Marketplace entries restored across all three catalogs (Claude, Cursor, Codex .agents), parity preserved.
  • Release wiring restored: release-please package + manifest entry at 1.3.0, src/release metadata/component code, test fixtures (test count 885 -> 889).
  • Coding-tutor's cursor manifest homepage/repository and its marketplace entry homepage point at this fork, matching the manifest treatment in fix(seo): repoint fork metadata and install docs, add SEO/GEO positioning #6. The compound-engineering entry is untouched here (owned by fix(seo): repoint fork metadata and install docs, add SEO/GEO positioning #6).
  • Confirmed no legacy-cleanup registry references coding-tutor, so restored user installs will not be swept on upgrade.

Verification

  • bun test: 889 pass / 0 fail
  • bun run release:validate: in sync

Interaction with #6

The SEO PR's README comparison table claims "bundled plugins: 1 (coding-tutor removed here)". If both PRs merge, that row is stale — a fixup on seo-geo-loop removes it.

Summary by CodeRabbit

  • New Features

    • Added the Coding Tutor plugin for personalized AI-driven coding tutorials built from your existing projects, featuring spaced-repetition quizzes to reinforce learning and progress tracking across your development journey.
  • Documentation

    • Added complete plugin documentation, including setup instructions, available commands (/teach-me, /quiz-me, /sync-tutorials), onboarding workflows, and comprehensive tutorial management guidelines for optimal learning experience.

User-directed restoration; reverts 159cfee (plugin tree, marketplace
entries across all three catalogs, release-please package + manifest
entry at 1.3.0, release metadata/component code, test fixtures).
Plugin content verified byte-identical to upstream/main current state.
Cursor manifest homepage/repository and the marketplace entry homepage
repointed to the fork, matching the manifest treatment in PR #6.

Op: extend
Copilot AI review requested due to automatic review settings June 7, 2026 15:42
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This pull request adds a new coding-tutor plugin to the codebase. The change registers the plugin across marketplace files, creates platform-specific manifests, integrates it into release automation, documents its features and skills, provides helper scripts for tutorial management, and updates tests to cover the new plugin throughout the test suite.

Changes

Coding Tutor Plugin Addition

Layer / File(s) Summary
Plugin Type Definition and Marketplace Registration
src/release/types.ts, .agents/plugins/marketplace.json, .claude-plugin/marketplace.json, .cursor-plugin/marketplace.json
ReleaseComponent type is extended to include "coding-tutor", and the plugin is registered in all three marketplace configuration files with appropriate metadata, source paths, and policies.
Plugin Manifest Files for All Platforms
plugins/coding-tutor/.claude-plugin/plugin.json, plugins/coding-tutor/.cursor-plugin/plugin.json, plugins/coding-tutor/.codex-plugin/plugin.json
Platform-specific plugin.json manifests define the plugin identity, version 1.3.0, description, author, license, keywords, interface metadata, capabilities, and Codex skill directory path.
Release Automation Configuration
.github/.release-please-manifest.json, .github/release-please-config.json, .github/workflows/release-preview.yml, src/release/components.ts, src/release/metadata.ts, src/targets/managed-artifacts.ts
Release-please versioning, GitHub Actions dispatch input, and component/metadata wiring updated to handle coding-tutor version detection, manifest synchronization, Codex parity validation, and preview overrides.
Plugin Documentation and Metadata
plugins/coding-tutor/CHANGELOG.md, plugins/coding-tutor/README.md, plugins/coding-tutor/commands/teach-me.md, plugins/coding-tutor/commands/quiz-me.md, plugins/coding-tutor/commands/sync-tutorials.md
Changelog entry for v1.3.0, README describing personalized tutoring and tutorial storage, and command documentation for teach-me, quiz-me, and sync-tutorials workflows.
Coding Tutor Skill Specification
plugins/coding-tutor/skills/coding-tutor/SKILL.md
Complete skill specification defining personalized tutoring flow, learner onboarding interview, teaching philosophy, tutorial template structure (frontmatter + Q&A + quiz history), and quiz behavior including spaced-repetition priority scoring by understanding level and last-assessed date.
Tutorial Management Scripts
plugins/coding-tutor/skills/coding-tutor/scripts/create_tutorial.py, plugins/coding-tutor/skills/coding-tutor/scripts/index_tutorials.py, plugins/coding-tutor/skills/coding-tutor/scripts/quiz_priority.py, plugins/coding-tutor/skills/coding-tutor/scripts/setup_tutorials.py
Python CLI tools for creating tutorial templates with git metadata, indexing tutorials from frontmatter with JSON/human-readable output, computing quiz priority via spaced-repetition intervals, and initializing a local tutorials repository with optional GitHub setup.
Test Suite Updates
tests/frontmatter.test.ts, tests/gemini-writer.test.ts, tests/opencode-writer.test.ts, tests/pi-writer.test.ts, tests/release-components.test.ts, tests/release-metadata.test.ts, tests/release-preview.test.ts, tests/skill-shell-safety.test.ts
All test files updated to include coding-tutor plugin in test fixtures and expectations, covering manifest validation, install-manifest namespacing, release component detection, metadata synchronization, and skill safety checks.

🐰 A tutor joins the warren so bright,

Teaching code with stories just right,

Quizzes spaced like rabbit hops far,

From your codebase, a learning star,

Hop along now, learn with delight! 📚

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 65.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: restoring the coding-tutor plugin. It uses a conventional commit format (feat scope) and is concrete, not vague.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch revert-coding-tutor

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the coding-tutor plugin, which provides personalized coding tutorials based on the user's codebase and tracks progress via spaced repetition quizzes. The changes include adding plugin manifests, commands, a core skill, and Python helper scripts for tutorial creation, indexing, and quiz prioritization, alongside corresponding updates to release metadata and tests. The review feedback highlights several critical robustness and cross-platform issues in the Python scripts, such as handling Windows path backslashes, sanitizing filenames, preventing silent file overwrites, improving the custom YAML frontmatter parser to ignore comments/empty lines, and handling partially initialized tutorial directories.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +29 to +30
if result.returncode == 0:
return result.stdout.strip().split('/')[-1]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

On Windows, git rev-parse --show-toplevel may return paths with backslashes (\\), causing split('/')[-1] to return the entire absolute path instead of just the repository name. Using Path.name is a robust, cross-platform way to extract the directory name.

Suggested change
if result.returncode == 0:
return result.stdout.strip().split('/')[-1]
if result.returncode == 0:
return Path(result.stdout.strip()).name

Comment on lines +51 to +53
def slugify(text):
"""Convert text to URL-friendly slug."""
return text.lower().replace(" ", "-").replace("_", "-")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If the topic contains characters that are invalid in Windows filenames (such as ?, :, *, etc.), creating the file will raise an OSError. Additionally, if the topic consists entirely of special characters, the slug will be empty. Cleaning the input to keep only alphanumeric characters and providing a fallback ensures cross-platform safety.

Suggested change
def slugify(text):
"""Convert text to URL-friendly slug."""
return text.lower().replace(" ", "-").replace("_", "-")
def slugify(text):
"""Convert text to URL-friendly slug."""
cleaned = "".join(c for c in text if c.isalnum() or c in " -_")
slug = cleaned.lower().replace(" ", "-").replace("_", "-")
return slug if slug else "tutorial"

Comment on lines +81 to +82
filename = f"{date_str_filename}-{slug}.md"
filepath = output_dir / filename

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If a tutorial with the same name is created on the same day, filepath.write_text(template) will silently overwrite the existing file, leading to potential data loss. Raising a FileExistsError prevents accidental overwrites.

Suggested change
filename = f"{date_str_filename}-{slug}.md"
filepath = output_dir / filename
filename = f"{date_str_filename}-{slug}.md"
filepath = output_dir / filename
if filepath.exists():
raise FileExistsError(f"Tutorial already exists at {filepath}. Aborting to prevent overwriting your work.")

Comment on lines +46 to +48
for line in frontmatter_text.split('\n'):
line = line.strip()
if ':' in line:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If the frontmatter contains empty lines or comments that happen to contain a colon (e.g., # Note: some comment), the simple parser will incorrectly treat them as key-value pairs. Skipping empty lines and comments starting with # makes the parser more robust.

Suggested change
for line in frontmatter_text.split('\n'):
line = line.strip()
if ':' in line:
for line in frontmatter_text.split('\n'):
line = line.strip()
if not line or line.startswith('#'):
continue
if ':' in line:

Comment on lines +52 to +54
for line in frontmatter_text.split('\n'):
line = line.strip()
if ':' in line:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If the frontmatter contains empty lines or comments with colons, the parser will incorrectly treat them as key-value pairs. Skipping empty lines and comments starting with # prevents this.

Suggested change
for line in frontmatter_text.split('\n'):
line = line.strip()
if ':' in line:
for line in frontmatter_text.split('\n'):
line = line.strip()
if not line or line.startswith('#'):
continue
if ':' in line:

Comment on lines +55 to +60
if repo_path.exists():
return True, f"Tutorials repo already exists at {repo_path.resolve()}"

try:
# Create directory
repo_path.mkdir(parents=True)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If the directory ~/coding-tutor-tutorials/ already exists but is not a git repository (e.g., if it was created manually or partially set up), the script will currently return early without initializing git or creating the required files. If we bypass the early return when .git is missing, the subsequent repo_path.mkdir(parents=True) will raise a FileExistsError because exist_ok=True is not specified. Checking for .git and using exist_ok=True allows safe initialization of existing directories.

Suggested change
if repo_path.exists():
return True, f"Tutorials repo already exists at {repo_path.resolve()}"
try:
# Create directory
repo_path.mkdir(parents=True)
if repo_path.exists() and (repo_path / ".git").exists():
return True, f"Tutorials repo already exists at {repo_path.resolve()}"
try:
# Create directory
repo_path.mkdir(parents=True, exist_ok=True)

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Restores the coding-tutor plugin subtree (skills/commands/manifests) and re-integrates it into this fork’s release + marketplace wiring so it is versioned, validated, and shipped alongside the existing compound-engineering plugin.

Changes:

  • Reintroduces plugins/coding-tutor/** (skill content + helper scripts, commands, and plugin manifests for Claude/Cursor/Codex).
  • Extends release automation to treat coding-tutor as a first-class release component (release preview overrides, release-please config/manifest, metadata sync).
  • Updates tests and marketplace catalogs to include/validate the restored plugin across supported surfaces.

Reviewed changes

Copilot reviewed 31 out of 31 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
tests/skill-shell-safety.test.ts Expands shell-safety fixture coverage to include coding-tutor skills directory.
tests/release-preview.test.ts Exercises release preview override behavior for the coding-tutor component.
tests/release-metadata.test.ts Extends release metadata fixtures/parity tests to include coding-tutor manifests + marketplace entries.
tests/release-components.test.ts Ensures component detection and scope parsing cover coding-tutor.
tests/pi-writer.test.ts Adjusts multi-plugin namespacing test fixture to use coding-tutor as the secondary plugin name.
tests/opencode-writer.test.ts Adjusts multi-plugin namespacing + legacy-migration fixtures to use coding-tutor.
tests/gemini-writer.test.ts Adjusts multi-plugin namespacing fixtures to use coding-tutor.
tests/frontmatter.test.ts Adds coding-tutor plugin root to frontmatter/YAML validity checks.
src/targets/managed-artifacts.ts Updates inline documentation example for plugin-scoped managed paths.
src/release/types.ts Adds coding-tutor to the ReleaseComponent union.
src/release/metadata.ts Syncs coding-tutor plugin manifest versions and enforces Codex parity/skills checks.
src/release/components.ts Adds coding-tutor component detection, scope mapping, and version loading.
plugins/coding-tutor/skills/coding-tutor/SKILL.md Introduces the coding-tutor skill definition and operating instructions.
plugins/coding-tutor/skills/coding-tutor/scripts/setup_tutorials.py Adds helper script to create/init the user’s tutorials repository.
plugins/coding-tutor/skills/coding-tutor/scripts/quiz_priority.py Adds helper script to prioritize quizzes via spaced repetition intervals.
plugins/coding-tutor/skills/coding-tutor/scripts/index_tutorials.py Adds helper script to index tutorial frontmatter into JSON/human output.
plugins/coding-tutor/skills/coding-tutor/scripts/create_tutorial.py Adds helper script to generate new tutorial templates with frontmatter.
plugins/coding-tutor/README.md Adds plugin README covering purpose, install, features, commands, and storage.
plugins/coding-tutor/commands/teach-me.md Adds teach-me command stub for the plugin.
plugins/coding-tutor/commands/sync-tutorials.md Adds sync-tutorials command instructions for backing up tutorials via git/GitHub.
plugins/coding-tutor/commands/quiz-me.md Adds quiz-me command stub for the plugin.
plugins/coding-tutor/CHANGELOG.md Restores coding-tutor changelog entry (v1.3.0).
plugins/coding-tutor/.cursor-plugin/plugin.json Restores Cursor plugin manifest for coding-tutor (v1.3.0).
plugins/coding-tutor/.codex-plugin/plugin.json Restores Codex plugin manifest for coding-tutor (v1.3.0) including skills path.
plugins/coding-tutor/.claude-plugin/plugin.json Restores Claude plugin manifest for coding-tutor (v1.3.0).
.github/workflows/release-preview.yml Adds a coding-tutor bump override input to the release preview workflow.
.github/release-please-config.json Adds release-please package config for plugins/coding-tutor + version extra-files.
.github/.release-please-manifest.json Adds manifest entry for plugins/coding-tutor at 1.3.0.
.cursor-plugin/marketplace.json Adds coding-tutor entry to the Cursor marketplace catalog.
.claude-plugin/marketplace.json Adds coding-tutor entry to the Claude marketplace catalog (source points at restored plugin).
.agents/plugins/marketplace.json Adds coding-tutor entry to the Codex .agents marketplace catalog.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -0,0 +1,214 @@
---
name: coding-tutor
description: Personalized coding tutorials that build on your existing knowledge and use your actual codebase for examples. Creates a persistent learning trail that compounds over time using the power of AI, spaced repetition and quizes.

3. **Who are you**: Tell me a bit about yourself - imagine we just met at a coworking space. - Get context that shapes how to teach them.

4. **Optional**: Based on the above answers, you may ask upto one optional 4th question if it will make your understanding of the learner richer.

## Teaching Philosophy

Our general goal is to take the user from newbie to a senior engineer in record time. One at par with engineers at companies like 37 Signals or Vercel.
description: One-paragraph summary of what this tutorial covers
understanding_score: null # null until quizzed, then 1-10 based on quiz performance
last_quizzed: null # null until first quiz, then DD-MM-YYYY
prerequisites: [~/coding-tutor-tutorials/tutorial_1_name.md, ~/coding-tutor-tutorials/tutorial_2_name.md, (upto 3 other existing tutorials)]
Comment on lines +15 to +19
## Install

```
/plugin install coding-tutor@claude-code-essentials
```

README_CONTENT = """# Coding Tutor - My Learning Journey

This repository contains my personalized coding tutorials created with the [coding-tutor](https://github.com/nityeshaga/claude-code-essentials) Claude Code plugin.
Comment on lines +12 to +17
import argparse
import json
import re
import subprocess
import sys
from pathlib import Path
Comment on lines +11 to +15
import argparse
import re
import subprocess
from datetime import datetime
from pathlib import Path

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (1)
plugins/coding-tutor/skills/coding-tutor/scripts/index_tutorials.py (1)

25-78: ⚡ Quick win

Consider extracting frontmatter parsing to a shared utility module.

The extract_frontmatter() logic (regex matching, key:value parsing, null/list handling) is duplicated in quiz_priority.py (lines 39-78) with minor variations. This duplication increases maintenance burden and risks divergence.

♻️ Suggested approach

Create a shared frontmatter_parser.py module in the scripts/ directory with a unified parse_frontmatter(filepath) function that both scripts can import. This centralizes the regex pattern, null-handling logic, and list-parsing conventions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/coding-tutor/skills/coding-tutor/scripts/index_tutorials.py` around
lines 25 - 78, The extract_frontmatter function duplicates parsing logic found
in quiz_priority.py; refactor by creating a new shared utility (e.g.,
scripts/frontmatter_parser.py) that exposes a single parse_frontmatter(filepath)
function implementing the YAML frontmatter regex, key:value parsing, null
handling for understanding_score and last_quizzed, and list parsing for
prerequisites, then replace the local extract_frontmatter implementations in
both index_tutorials.py (extract_frontmatter) and quiz_priority.py with imports
from parse_frontmatter to eliminate duplication and centralize behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/coding-tutor/README.md`:
- Around line 17-19: The fenced command block containing `/plugin install
coding-tutor@claude-code-essentials` should use a typed fence to satisfy
markdown linting; update the triple-backtick fence that wraps that command to
include a shell language tag (e.g., bash) so the block becomes a proper code
fence with a language identifier.

In `@plugins/coding-tutor/skills/coding-tutor/scripts/create_tutorial.py`:
- Line 199: Remove the unnecessary f-string prefix on the print call that has no
placeholders: change the statement starting with print(f"Edit the file to add
content and update the frontmatter") to a plain string (remove the leading f) so
it reads print("Edit the file to add content and update the frontmatter");
update the same call in create_tutorial.py where that print occurs.
- Around line 51-53: The slugify function currently only replaces spaces and
underscores; update slugify to fully sanitize topic strings by normalizing
Unicode (e.g., NFKD) and then removing or replacing all non-alphanumeric
characters with hyphens using a regex, collapse consecutive hyphens into one,
and trim leading/trailing hyphens so outputs are lowercase, filesystem-safe
slugs (refer to the slugify function in create_tutorial.py).
- Around line 92-93: The frontmatter currently writes concepts as a raw comma
string via the template variable (template = f"""---\nconcepts:
{concepts}\n"""), which violates the skill contract; update the code that builds
the template in create_tutorial.py to render concepts as a bracketed,
comma-space separated list (e.g., transform the existing concepts value into
"[Redux, Context, State]" before injecting into the template), ensuring you
reference the same variable name (concepts) and the template string so
downstream parsers (index_tutorials.py, quiz_priority.py) receive the expected
bracketed list format.

In `@plugins/coding-tutor/skills/coding-tutor/scripts/index_tutorials.py`:
- Line 139: The string passed to output.append currently uses an unnecessary
f-string: output.append(f"   Understanding: not quizzed yet"); change it to a
plain string by removing the leading "f" so it reads output.append("  
Understanding: not quizzed yet") to avoid the extraneous f-prefix.

In `@plugins/coding-tutor/skills/coding-tutor/SKILL.md`:
- Line 3: Fix the frontmatter typo in SKILL.md by updating the description
field: replace the word "quizes" with the correct spelling "quizzes" in the
description frontmatter line so the user-facing metadata is accurate (look for
the description key in plugins/coding-tutor/skills/coding-tutor/SKILL.md).
- Around line 207-212: The fenced code block showing the quiz history in
SKILL.md lacks a language tag; update the opening fence for the "### Quiz -
DD-MM-YYYY" block (the triple backticks before the quiz content) to include a
language such as markdown or text (e.g., change ``` to ```markdown) so the block
satisfies markdown lint rules.
- Around line 165-166: Replace the Unicode arrow characters "→" with ASCII "->"
in the example lines inside SKILL.md (specifically the examples showing
Explicit: "Quiz me on React hooks" → quiz that specific concept and Open: "Quiz
me on something" → run `python3
${CLAUDE_PLUGIN_ROOT}/skills/coding-tutor/scripts/quiz_priority.py`...), and
also update the other occurrence mentioned (line 211) so all terminal/example
arrows use ASCII -> to comply with the coding guideline; search the file for "→"
and replace with "->" within code/terminal/example blocks.
- Around line 38-39: The skill's guidance to "Ask these three questions, one at
a time" lacks explicit instruction to use the platform blocking question tool
and a fallback; update the skill text where questions are prompted (e.g., the
onboarding and quiz steps around the current "Ask these three questions, one at
a time" passage and the other instances at lines ~81-84 and ~183-184) to
instruct: call the platform blocking question API (AskUserQuestion /
request_user_input / ask_user) for each question and wait for the response, and
if the blocking tool is unavailable, present numbered options as a fallback and
parse the chosen number; mention the exact tool names (AskUserQuestion,
request_user_input, ask_user) so implementers know which runtime calls to use.

---

Nitpick comments:
In `@plugins/coding-tutor/skills/coding-tutor/scripts/index_tutorials.py`:
- Around line 25-78: The extract_frontmatter function duplicates parsing logic
found in quiz_priority.py; refactor by creating a new shared utility (e.g.,
scripts/frontmatter_parser.py) that exposes a single parse_frontmatter(filepath)
function implementing the YAML frontmatter regex, key:value parsing, null
handling for understanding_score and last_quizzed, and list parsing for
prerequisites, then replace the local extract_frontmatter implementations in
both index_tutorials.py (extract_frontmatter) and quiz_priority.py with imports
from parse_frontmatter to eliminate duplication and centralize behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2304ae4c-7dfc-415f-a793-42b5fda61a7f

📥 Commits

Reviewing files that changed from the base of the PR and between 03aae87 and 2395458.

📒 Files selected for processing (31)
  • .agents/plugins/marketplace.json
  • .claude-plugin/marketplace.json
  • .cursor-plugin/marketplace.json
  • .github/.release-please-manifest.json
  • .github/release-please-config.json
  • .github/workflows/release-preview.yml
  • plugins/coding-tutor/.claude-plugin/plugin.json
  • plugins/coding-tutor/.codex-plugin/plugin.json
  • plugins/coding-tutor/.cursor-plugin/plugin.json
  • plugins/coding-tutor/CHANGELOG.md
  • plugins/coding-tutor/README.md
  • plugins/coding-tutor/commands/quiz-me.md
  • plugins/coding-tutor/commands/sync-tutorials.md
  • plugins/coding-tutor/commands/teach-me.md
  • plugins/coding-tutor/skills/coding-tutor/SKILL.md
  • plugins/coding-tutor/skills/coding-tutor/scripts/create_tutorial.py
  • plugins/coding-tutor/skills/coding-tutor/scripts/index_tutorials.py
  • plugins/coding-tutor/skills/coding-tutor/scripts/quiz_priority.py
  • plugins/coding-tutor/skills/coding-tutor/scripts/setup_tutorials.py
  • src/release/components.ts
  • src/release/metadata.ts
  • src/release/types.ts
  • src/targets/managed-artifacts.ts
  • tests/frontmatter.test.ts
  • tests/gemini-writer.test.ts
  • tests/opencode-writer.test.ts
  • tests/pi-writer.test.ts
  • tests/release-components.test.ts
  • tests/release-metadata.test.ts
  • tests/release-preview.test.ts
  • tests/skill-shell-safety.test.ts

Comment on lines +17 to +19
```
/plugin install coding-tutor@claude-code-essentials
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language tag to the fenced command block.

Line 17 should use a typed fence (for example bash) to satisfy markdown linting.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 17-17: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/coding-tutor/README.md` around lines 17 - 19, The fenced command
block containing `/plugin install coding-tutor@claude-code-essentials` should
use a typed fence to satisfy markdown linting; update the triple-backtick fence
that wraps that command to include a shell language tag (e.g., bash) so the
block becomes a proper code fence with a language identifier.

Sources: Coding guidelines, Linters/SAST tools

Comment on lines +51 to +53
def slugify(text):
"""Convert text to URL-friendly slug."""
return text.lower().replace(" ", "-").replace("_", "-")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Harden slugify() to sanitize all special characters.

The current implementation only replaces spaces and underscores. Topic names with characters like :, /, (, ), &, or quotes will produce invalid filenames. For example, "React: Hooks & Effects" becomes "react:-hooks-&-effects.md", which may fail on some filesystems or cause shell-escaping issues.

🛡️ Proposed fix using regex to strip non-alphanumerics
 def slugify(text):
     """Convert text to URL-friendly slug."""
-    return text.lower().replace(" ", "-").replace("_", "-")
+    import re
+    text = text.lower()
+    text = re.sub(r'[^\w\s-]', '', text)  # Remove non-alphanumeric except spaces/hyphens
+    text = re.sub(r'[-\s]+', '-', text)   # Collapse spaces/hyphens
+    return text.strip('-')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/coding-tutor/skills/coding-tutor/scripts/create_tutorial.py` around
lines 51 - 53, The slugify function currently only replaces spaces and
underscores; update slugify to fully sanitize topic strings by normalizing
Unicode (e.g., NFKD) and then removing or replacing all non-alphanumeric
characters with hyphens using a regex, collapse consecutive hyphens into one,
and trim leading/trailing hyphens so outputs are lowercase, filesystem-safe
slugs (refer to the slugify function in create_tutorial.py).

Comment on lines +92 to +93
template = f"""---
concepts: {concepts}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix concepts frontmatter format to match the skill contract.

Line 93 generates concepts: {concepts} which outputs a raw comma-separated string (e.g., concepts: Redux,Context,State). However, the skill specification (SKILL.md:85-98) and downstream scripts (index_tutorials.py, quiz_priority.py) expect bracketed list syntax: concepts: [Redux, Context, State]. This contract violation will cause parsing failures when indexing or prioritizing tutorials.

🐛 Proposed fix to emit bracketed list format
     # Create tutorial template with YAML frontmatter and embedded guidance
+    # Format concepts as bracketed list for YAML compliance
+    if concepts:
+        concepts_formatted = f"[{concepts}]"
+    else:
+        concepts_formatted = "[]"
+    
     template = f"""---
-concepts: {concepts}
+concepts: {concepts_formatted}
 source_repo: {repo_name}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
template = f"""---
concepts: {concepts}
# Format concepts as bracketed list for YAML compliance
if concepts:
concepts_formatted = f"[{concepts}]"
else:
concepts_formatted = "[]"
template = f"""---
concepts: {concepts_formatted}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/coding-tutor/skills/coding-tutor/scripts/create_tutorial.py` around
lines 92 - 93, The frontmatter currently writes concepts as a raw comma string
via the template variable (template = f"""---\nconcepts: {concepts}\n"""), which
violates the skill contract; update the code that builds the template in
create_tutorial.py to render concepts as a bracketed, comma-space separated list
(e.g., transform the existing concepts value into "[Redux, Context, State]"
before injecting into the template), ensuring you reference the same variable
name (concepts) and the template string so downstream parsers
(index_tutorials.py, quiz_priority.py) receive the expected bracketed list
format.

try:
filepath = create_tutorial(args.topic, args.concepts, args.output_dir)
print(f"Created tutorial template: {filepath}")
print(f"Edit the file to add content and update the frontmatter")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove extraneous f prefix from string literal.

Line 199 uses an f-string with no placeholders.

♻️ Proposed fix
-        print(f"Edit the file to add content and update the frontmatter")
+        print("Edit the file to add content and update the frontmatter")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
print(f"Edit the file to add content and update the frontmatter")
print("Edit the file to add content and update the frontmatter")
🧰 Tools
🪛 Ruff (0.15.15)

[error] 199-199: f-string without any placeholders

Remove extraneous f prefix

(F541)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/coding-tutor/skills/coding-tutor/scripts/create_tutorial.py` at line
199, Remove the unnecessary f-string prefix on the print call that has no
placeholders: change the statement starting with print(f"Edit the file to add
content and update the frontmatter") to a plain string (remove the leading f) so
it reads print("Edit the file to add content and update the frontmatter");
update the same call in create_tutorial.py where that print occurs.

output.append(f" Description: {tutorial['description']}")
score = tutorial['understanding_score']
if score is None:
output.append(f" Understanding: not quizzed yet")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove extraneous f prefix from string literal.

Line 139 uses an f-string with no placeholders.

♻️ Proposed fix
-            output.append(f"   Understanding: not quizzed yet")
+            output.append("   Understanding: not quizzed yet")
🧰 Tools
🪛 Ruff (0.15.15)

[error] 139-139: f-string without any placeholders

Remove extraneous f prefix

(F541)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/coding-tutor/skills/coding-tutor/scripts/index_tutorials.py` at line
139, The string passed to output.append currently uses an unnecessary f-string:
output.append(f"   Understanding: not quizzed yet"); change it to a plain string
by removing the leading "f" so it reads output.append("   Understanding: not
quizzed yet") to avoid the extraneous f-prefix.

@@ -0,0 +1,214 @@
---
name: coding-tutor
description: Personalized coding tutorials that build on your existing knowledge and use your actual codebase for examples. Creates a persistent learning trail that compounds over time using the power of AI, spaced repetition and quizes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix typo in frontmatter description (quizes -> quizzes).

This is user-facing metadata; correcting it avoids downstream copy drift in generated docs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/coding-tutor/skills/coding-tutor/SKILL.md` at line 3, Fix the
frontmatter typo in SKILL.md by updating the description field: replace the word
"quizes" with the correct spelling "quizzes" in the description frontmatter line
so the user-facing metadata is accurate (look for the description key in
plugins/coding-tutor/skills/coding-tutor/SKILL.md).

Comment on lines +38 to +39
Ask these three questions, one at a time. Wait for each answer before asking the next.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Specify blocking question-tool usage wherever the skill asks questions.

The onboarding and quiz flows require sequential user responses, but the skill doesn’t instruct the runtime to use platform blocking question tools (and fallback behavior). Add explicit guidance for AskUserQuestion/request_user_input/ask_user plus numbered-option fallback when unavailable.

Based on learnings: “When a skill needs to ask the user a question, use the platform's blocking question tool … with numbered options as fallback when the blocking tool is unavailable.”

Also applies to: 81-84, 183-184

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/coding-tutor/skills/coding-tutor/SKILL.md` around lines 38 - 39, The
skill's guidance to "Ask these three questions, one at a time" lacks explicit
instruction to use the platform blocking question tool and a fallback; update
the skill text where questions are prompted (e.g., the onboarding and quiz steps
around the current "Ask these three questions, one at a time" passage and the
other instances at lines ~81-84 and ~183-184) to instruct: call the platform
blocking question API (AskUserQuestion / request_user_input / ask_user) for each
question and wait for the response, and if the blocking tool is unavailable,
present numbered options as a fallback and parse the chosen number; mention the
exact tool names (AskUserQuestion, request_user_input, ask_user) so implementers
know which runtime calls to use.

Source: Learnings

Comment on lines +165 to +166
- Explicit: "Quiz me on React hooks" → quiz that specific concept
- Open: "Quiz me on something" → run `python3 ${CLAUDE_PLUGIN_ROOT}/skills/coding-tutor/scripts/quiz_priority.py` to get a prioritized list based on spaced repetition, then choose what to quiz

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace Unicode arrows in examples with ASCII arrows.

Use ASCII -> instead of in these terminal/example lines to match markdown guidance.

As per coding guidelines: “Prefer ASCII arrows (->-, <-) over Unicode arrows in code blocks and terminal examples.”

Also applies to: 211-211

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/coding-tutor/skills/coding-tutor/SKILL.md` around lines 165 - 166,
Replace the Unicode arrow characters "→" with ASCII "->" in the example lines
inside SKILL.md (specifically the examples showing Explicit: "Quiz me on React
hooks" → quiz that specific concept and Open: "Quiz me on something" → run
`python3
${CLAUDE_PLUGIN_ROOT}/skills/coding-tutor/scripts/quiz_priority.py`...), and
also update the other occurrence mentioned (line 211) so all terminal/example
arrows use ASCII -> to comply with the coding guideline; search the file for "→"
and replace with "->" within code/terminal/example blocks.

Source: Coding guidelines

Comment on lines +207 to +212
```
### Quiz - DD-MM-YYYY
**Q:** [Question asked]
**A:** [Brief summary of their response and what it revealed about understanding]
Score updated: 5 → 7
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a language tag to the quiz-history fenced block.

Line 207 should declare a fence language (for example markdown or text) to satisfy markdown lint rules.

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 207-207: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/coding-tutor/skills/coding-tutor/SKILL.md` around lines 207 - 212,
The fenced code block showing the quiz history in SKILL.md lacks a language tag;
update the opening fence for the "### Quiz - DD-MM-YYYY" block (the triple
backticks before the quiz content) to include a language such as markdown or
text (e.g., change ``` to ```markdown) so the block satisfies markdown lint
rules.

Source: Linters/SAST tools

@metaphorics metaphorics merged commit 459c099 into main Jun 7, 2026
4 checks passed
@metaphorics metaphorics deleted the revert-coding-tutor branch June 7, 2026 16:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants