diff --git a/.github/instructions/context-engineering.instructions.md b/.github/instructions/context-engineering.instructions.md new file mode 100644 index 0000000..99658fd --- /dev/null +++ b/.github/instructions/context-engineering.instructions.md @@ -0,0 +1,44 @@ +--- +description: 'Guidelines for structuring code and projects to maximize GitHub Copilot effectiveness through better context management' +applyTo: '**' +--- + +# Context Engineering + +Principles for helping GitHub Copilot understand your codebase and provide better suggestions. + +## Project Structure + +- **Use descriptive file paths**: `src/auth/middleware.ts` > `src/utils/m.ts`. Copilot uses paths to infer intent. +- **Colocate related code**: Keep components, tests, types, and hooks together. One search pattern should find everything related. +- **Export public APIs from index files**: What's exported is the contract; what's not is internal. This helps Copilot understand boundaries. + +## Code Patterns + +- **Prefer explicit types over inference**: Type annotations are context. `function getUser(id: string): Promise` tells Copilot more than `function getUser(id)`. +- **Use semantic names**: `activeAdultUsers` > `x`. Self-documenting code is AI-readable code. +- **Define constants**: `MAX_RETRY_ATTEMPTS = 3` > magic number `3`. Named values carry meaning. + +## Working with Copilot + +- **Keep relevant files open in tabs**: Copilot uses open tabs as context signals. Working on auth? Open auth-related files. +- **Position cursor intentionally**: Copilot prioritizes code near your cursor. Put cursor where context matters. +- **Use Copilot Chat for complex tasks**: Inline completions have minimal context. Chat mode sees more files. + +## Context Hints + +- **Add a COPILOT.md file**: Document architecture decisions, patterns, and conventions Copilot should follow. +- **Use strategic comments**: At the top of complex modules, briefly describe the flow or purpose. +- **Reference patterns explicitly**: "Follow the same pattern as `src/api/users.ts`" gives Copilot a concrete example. + +## Multi-File Changes + +- **Describe scope first**: Tell Copilot all files involved before asking for changes. "I need to update the User model, API endpoint, and tests." +- **Work incrementally**: One file at a time, verifying each change. Don't ask for everything at once. +- **Check understanding**: Ask "What files would you need to see?" before complex refactors. + +## When Copilot Struggles + +- **Missing context**: Open the relevant files in tabs, or explicitly paste code snippets. +- **Stale suggestions**: Copilot may not see recent changes. Re-open files or restart the session. +- **Generic answers**: Be more specific. Add constraints, mention frameworks, reference existing code. diff --git a/.github/instructions/hooks.instructions.md b/.github/instructions/hooks.instructions.md new file mode 100644 index 0000000..fea0609 --- /dev/null +++ b/.github/instructions/hooks.instructions.md @@ -0,0 +1,597 @@ +--- +description: 'Portable guidance for authoring safe, fast, and clear hooks and reusable hook examples' +applyTo: '.github/hooks/**, hooks/**' +--- + +# Hook Authoring Guidelines + +Hooks are **small, deterministic commands or scripts** that run at specific lifecycle events. +An awesome hook does one clear job, runs quickly, and makes its side effects explicit. + +## Folder Structure + +A GitHub Copilot hook lives in `.github/hooks/` inside your repository: + +```text +.github/ +└── hooks/ + ├── block-dangerous-commands.json ← hook config (which event, which script, options) + └── scripts/ + ├── block-dangerous-commands.sh ← Bash implementation + └── block-dangerous-commands.ps1 ← PowerShell implementation (optional if Bash-only) +``` + +You can have multiple `.json` files — each one registers hooks for one or more events. The host loads all of them. + +## The Config File + +Each `.json` file maps events to an array of hook entries. + +- **Command hooks** (`type: "command"`): run a local script. The host passes event JSON on stdin, your script responds through exit code and stdout. + +### Config example + +```json +{ + "version": 1, + "hooks": { + "preToolUse": [ + { + "matcher": "bash", + "type": "command", + "bash": "./.github/hooks/scripts/block-dangerous-commands.sh", + "powershell": "./.github/hooks/scripts/block-dangerous-commands.ps1", + "cwd": ".", + "timeoutSec": 5, + "env": { + "BLOCK_MODE": "deny" + } + } + ] + } +} +``` + +### Config fields + +| Field | Required | What it does | +| ---- | ---- | ---- | +| `type` | yes | `"command"` for scripts | +| `matcher` | no | Host-level filter — hook only fires when the tool name matches this value (e.g. `"bash"`, `"powershell"`, `"edit"`, `"create"`). Locally verified working in Copilot CLI v1.0.36; not yet used in repo hook samples. | +| `bash` | one or both | Command line invoked on Unix / Bash-capable hosts | +| `powershell` | one or both | Command line invoked on Windows / PowerShell-capable hosts | +| `cwd` | no | Working directory, relative to repo root | +| `timeoutSec` | no | Max seconds before the host kills the process (default 30) | +| `env` | no | Extra process environment variables passed to the script | + +### Why matchers matter + +Without a matcher, every `preToolUse` hook fires on **every** tool call. Your script starts with boilerplate like: + +```bash +tool_name="$(printf '%s' "$payload" | jq -r '.toolName')" +[[ "$tool_name" != "bash" ]] && exit 0 +``` + +With a matcher, the host does this filtering for you — no boilerplate, no process spawn for irrelevant tools. This will likely become the standard pattern once the feature stabilizes. + +If your hooks must work on both the CLI and the cloud agent (or on older CLI versions), keep the in-script filtering as a fallback even when using matchers. + +### `env` — static configuration for your script + +`env` is a **standard host field**. The keys inside it are **author-defined variables** — you choose the names and values. + +They arrive as **process environment variables**, not inside the stdin JSON payload. Use them for static configuration that should not be hardcoded: + +| Pattern | Example | +| ---- | ---- | +| Mode flag | `"BLOCK_MODE": "deny"` — same script logs in one repo, blocks in another | +| Threshold | `"MAX_CHANGED_FILES": "20"` | +| Path | `"AUDIT_LOG_PATH": ".github/logs/hooks.log"` | +| Feature toggle | `"ENABLE_NOTIFICATIONS": "false"` | + +### `bash` and `powershell` — when to provide one or both + +The host picks whichever entry matches the current environment. It does not run both, and does not fall back from one to the other. + +| Situation | Provide | +| ---- | ---- | +| Private hook, one known platform | Only that platform's entry | +| Published hook claiming cross-platform support | Both entries | +| Single cross-platform runtime (Python, Node, pwsh) | Expose the same script through both entries | +| Bash-only dependency | `bash` only | +| Windows-only dependency | `powershell` only | + +Cross-platform example using Python through both entries: + +```json +{ + "type": "command", + "bash": "python3 ./.github/hooks/scripts/check.py", + "powershell": "python .\\.github\\hooks\\scripts\\check.py" +} +``` + +## The Script Contract + +Every hook script follows the same basic contract: read JSON from stdin, do work, and respond through exit code, stdout, and stderr. + +**Important**: `toolArgs` is a **JSON string**, not a nested object. You must parse it a second time to access its fields. + +### Reading stdin and responding — Bash and PowerShell + +**Bash**: + +```bash +#!/usr/bin/env bash +set -euo pipefail +payload="$(cat)" +tool_name="$(printf '%s' "$payload" | jq -r '.toolName')" +tool_args="$(printf '%s' "$payload" | jq -r '.toolArgs')" +command="$(printf '%s' "$tool_args" | jq -r '.command // ""')" +``` + +**PowerShell**: + +```powershell +Set-StrictMode -Version Latest +$payload = [Console]::In.ReadToEnd() | ConvertFrom-Json +$toolArgs = $payload.toolArgs | ConvertFrom-Json +$command = $toolArgs.command +``` + +To deny in `preToolUse` (PowerShell): + +```powershell +@{ permissionDecision = 'deny'; permissionDecisionReason = 'Blocked by policy' } | + ConvertTo-Json -Compress +exit 0 +``` + +### What the script receives + +| Input | What it carries | +| ---- | ---- | +| `stdin` | One JSON payload describing the current event | +| process environment | Normal env vars plus any you defined under `env` in the config | +| working directory | `cwd` from the config, or the host default | + +### How the script responds + +| Channel | Purpose | +| ---- | ---- | +| exit `0` | Script succeeded — host continues unless stdout carried a structured deny | +| non-zero exit | **Blocks the triggering action** and signals hook failure | +| `stdout` | Structured machine-readable output — only for events that document a stdout schema (like `preToolUse`) | +| `stderr` | Human-readable diagnostics for logs | + +### Exit codes and deny: the full picture + +The deny mechanism **depends on the event**: + +| Event type | How to allow | How to deny / block | +| ---- | ---- | ---- | +| `preToolUse` | exit `0`, empty or `{"permissionDecision":"allow"}` on stdout | **Preferred**: exit `0` + `{"permissionDecision":"deny","permissionDecisionReason":"..."}` on stdout — gives the host a reason to show. **Also works**: non-zero exit blocks the tool call, but without a structured reason. | +| `userPromptSubmitted` | exit `0` | Non-zero exit blocks the prompt (stdout is ignored for this event) | +| `agentStop` | exit `0` | Non-zero exit blocks the action | +| Other events (`sessionStart`, `sessionEnd`, `postToolUse`, `errorOccurred`) | exit `0` | Non-zero exit signals failure; the host may skip subsequent hooks for that event | + +**Rule of thumb**: if the event has a structured stdout schema (like `preToolUse`), use it — it gives a clean reason and is the officially documented deny path. For events without structured stdout, non-zero exit is the practical block mechanism — this is confirmed by repo samples and learning hub docs, though the official GitHub reference does not explicitly document "non-zero = block" as a contract guarantee. + +### Example 1: Commit gate — block commits until lint, types, and tests pass + +**Why this pattern matters**: the deny reason includes the actual errors, so the agent sees what's broken and fixes it before trying again. This creates a self-correcting feedback loop — the most powerful thing hooks can do. + +**Event**: `preToolUse` — fires before the agent runs `git commit` + +**Config** — `.github/hooks/commit-gate.json`: + +```json +{ + "version": 1, + "hooks": { + "preToolUse": [ + { + "type": "command", + "bash": "./.github/hooks/scripts/commit-gate.sh", + "cwd": ".", + "timeoutSec": 120 + } + ] + } +} +``` + +**Script** — `.github/hooks/scripts/commit-gate.sh`: + +```bash +#!/usr/bin/env bash +set -euo pipefail + +payload="$(cat)" +tool_name="$(printf '%s' "$payload" | jq -r '.toolName')" + +# Only gate bash commands that are git commits +if [[ "$tool_name" != "bash" ]]; then exit 0; fi +command="$(printf '%s' "$payload" | jq -r '.toolArgs' | jq -r '.command // ""')" +if ! printf '%s' "$command" | grep -q "git commit"; then exit 0; fi + +CWD="$(printf '%s' "$payload" | jq -r '.cwd')" +ERRORS="" + +# 1. TypeScript type check +if [[ -f "$CWD/tsconfig.json" ]]; then + TSC_OUT=$(cd "$CWD" && npx tsc --noEmit 2>&1) || ERRORS="${ERRORS} +=== TypeScript Errors === +$(echo "$TSC_OUT" | head -30)" +fi + +# 2. Lint +if [[ -f "$CWD/package.json" ]]; then + HAS_LINT=$(jq -r '.scripts.lint // empty' "$CWD/package.json" 2>/dev/null) + if [[ -n "$HAS_LINT" ]]; then + LINT_OUT=$(cd "$CWD" && npm run lint --silent 2>&1) || ERRORS="${ERRORS} +=== Lint Errors === +$(echo "$LINT_OUT" | tail -30)" + fi + + # 3. Tests + HAS_TEST=$(jq -r '.scripts.test // empty' "$CWD/package.json" 2>/dev/null) + if [[ -n "$HAS_TEST" ]]; then + TEST_OUT=$(cd "$CWD" && CI=true npm test -- --watchAll=false 2>&1) || ERRORS="${ERRORS} +=== Test Failures === +$(echo "$TEST_OUT" | tail -30)" + fi +fi + +if [[ -n "$ERRORS" ]]; then + jq -nc --arg reason "Cannot commit — fix these issues first: +$ERRORS" \ + '{permissionDecision:"deny",permissionDecisionReason:$reason}' +fi +exit 0 +``` + +**What happens at runtime:** + +| Scenario | stdout | exit | Host action | +| ---- | ---- | ---- | ---- | +| All checks pass | empty | `0` | Commit proceeds | +| Lint fails | `{"permissionDecision":"deny","permissionDecisionReason":"Cannot commit — fix these issues first:\n=== Lint Errors ===\n..."}` | `0` | Blocks commit; agent sees the errors and fixes them | +| jq missing | empty | non-zero | Hook failure | + +### Example 2: Auto-format after file edits + +**Why this pattern matters**: the agent writes code, and your formatter runs immediately after — no manual step needed. The agent's next read of that file sees the formatted version. + +**Event**: `postToolUse` — fires after `edit` or `create` tool calls + +**Config** — `.github/hooks/format-on-save.json`: + +```json +{ + "version": 1, + "hooks": { + "postToolUse": [ + { + "type": "command", + "bash": "./.github/hooks/scripts/format-on-save.sh", + "cwd": ".", + "timeoutSec": 15 + } + ] + } +} +``` + +**Script** — `.github/hooks/scripts/format-on-save.sh`: + +```bash +#!/usr/bin/env bash +set -euo pipefail + +payload="$(cat)" +tool_name="$(printf '%s' "$payload" | jq -r '.toolName')" +result_type="$(printf '%s' "$payload" | jq -r '.toolResult.resultType // ""')" + +# Only format after successful file writes +case "$tool_name" in + edit|create) ;; + *) exit 0 ;; +esac +[[ "$result_type" != "success" ]] && exit 0 + +file_path="$(printf '%s' "$payload" | jq -r '.toolArgs' | jq -r '.path // ""')" +[[ -z "$file_path" || ! -f "$file_path" ]] && exit 0 + +# Run the project's formatter — adapt to your stack +if command -v npx >/dev/null 2>&1 && [[ -f "package.json" ]]; then + npx prettier --write "$file_path" 2>/dev/null || true +elif command -v dotnet >/dev/null 2>&1 && [[ "$file_path" == *.cs ]]; then + dotnet format --include "$file_path" 2>/dev/null || true +fi +exit 0 +``` + +**What happens at runtime:** + +| Scenario | What the hook does | exit | +| ---- | ---- | ---- | +| Agent edits `src/app.ts` successfully | Runs `prettier --write src/app.ts` | `0` | +| Agent runs `bash ls` | Skips (not a file-writing tool) | `0` | +| Prettier not installed | Silently skips formatting | `0` | + +### Example 3: Block dangerous commands with structured deny + +**Why this pattern matters**: the simplest guardrail — prevent destructive shell commands before they execute, with a clear reason the agent can read. + +**Event**: `preToolUse` — fires before any tool call + +**Config** — `.github/hooks/block-dangerous.json`: + +```json +{ + "version": 1, + "hooks": { + "preToolUse": [ + { + "type": "command", + "bash": "./.github/hooks/scripts/block-dangerous.sh", + "cwd": ".", + "timeoutSec": 5, + "env": { + "BLOCK_MODE": "deny" + } + } + ] + } +} +``` + +**Script** — `.github/hooks/scripts/block-dangerous.sh`: + +```bash +#!/usr/bin/env bash +set -euo pipefail + +payload="$(cat)" +block_mode="${BLOCK_MODE:-log}" +tool_name="$(printf '%s' "$payload" | jq -r '.toolName')" + +[[ "$tool_name" != "bash" ]] && exit 0 + +command="$(printf '%s' "$payload" | jq -r '.toolArgs' | jq -r '.command // ""')" + +if printf '%s' "$command" | grep -qE 'rm -rf /|git reset --hard|git clean -fd|git push.*--force'; then + # Truncate command to avoid leaking secrets in deny reason or logs + short_cmd="$(printf '%.80s' "$command")" + if [[ "$block_mode" == "deny" ]]; then + jq -cn --arg reason "Destructive command blocked: ${short_cmd}..." \ + '{permissionDecision:"deny",permissionDecisionReason:$reason}' + else + echo "Would block: ${short_cmd}..." >&2 + fi +fi +exit 0 +``` + +**What happens at runtime:** + +| Scenario | BLOCK_MODE | stdout | exit | Host action | +| ---- | ---- | ---- | ---- | ---- | +| Safe command | any | empty | `0` | Proceeds | +| `git push --force` | `deny` | `{"permissionDecision":"deny",...}` | `0` | Blocks with reason | +| `git push --force` | `log` | empty | `0` | Proceeds (log only) | + +## Event Types + +The full hooks reference is authoritative. **Always check it for the latest payload shapes** before writing a hook: + +- [Hooks configuration reference](https://docs.github.com/en/copilot/reference/hooks-configuration) +- [About hooks](https://docs.github.com/en/copilot/concepts/agents/cloud-agent/about-hooks) + +| Event | stdout | Typical use | +| ---- | ---- | ---- | +| `sessionStart` | **parsed** — `additionalContext` in stdout is injected into the session | Setup, validation, context injection, logging | +| `sessionEnd` | ignored | Cleanup, summaries | +| `userPromptSubmitted` | ignored | Auditing, prompt blocking | +| `preToolUse` | **parsed** — `permissionDecision`, `modifiedArgs`/`updatedInput`, `additionalContext` | Guardrails, deny/block, argument modification | +| `postToolUse` | ignored | Logging, formatting | +| `postToolUseFailure` | — | Recovery after a failed tool run | +| `agentStop` | — | Final validation | +| `subagentStart` | — | Subagent audit | +| `subagentStop` | — | Subagent output validation | +| `errorOccurred` | ignored | Diagnostics, alerts | +| `preCompact` | — | Pre-compaction work | +| `permissionRequest` | — | Approval workflow | + +### Payload schemas for common events + +These are the payload shapes from the hooks reference. Always verify against the [official reference](https://docs.github.com/en/copilot/reference/hooks-configuration) for the latest fields. + +**`sessionStart`** + +```json +{ + "timestamp": 1704614400000, + "cwd": "/path/to/project", + "source": "new", + "initialPrompt": "Create a new feature" +} +``` + +`source` is `"new"`, `"resume"`, or `"startup"`. `initialPrompt` is the user's first prompt if provided. + +**`sessionStart` stdout output** — the host parses stdout for: + +```json +{ + "additionalContext": "Current branch: main. Deploy target: staging." +} +``` + +`additionalContext` is injected directly into the session conversation, letting hooks provide environment-specific context dynamically. + +**`sessionEnd`** + +```json +{ + "timestamp": 1704618000000, + "cwd": "/path/to/project", + "reason": "complete" +} +``` + +`reason` is `"complete"`, `"error"`, `"abort"`, `"timeout"`, or `"user_exit"`. + +**`userPromptSubmitted`** + +```json +{ + "timestamp": 1704614500000, + "cwd": "/path/to/project", + "prompt": "Fix the authentication bug" +} +``` + +The field is `prompt` — the exact text the user submitted. + +**`preToolUse`** + +```json +{ + "timestamp": 1704614600000, + "cwd": "/path/to/project", + "toolName": "bash", + "toolArgs": "{\"command\":\"rm -rf dist\",\"description\":\"Clean build directory\"}" +} +``` + +`toolArgs` is a **JSON string** — parse it a second time to access its fields. + +**`preToolUse` stdout output** — the host parses stdout for: + +| Field | What it does | +| ---- | ---- | +| `permissionDecision` | `"deny"` blocks the tool call. `"allow"` and `"ask"` also accepted; only `"deny"` is currently processed. | +| `permissionDecisionReason` | Human-readable reason shown to the user | +| `modifiedArgs` or `updatedInput` | Replacement tool arguments — used instead of the originals | +| `additionalContext` | Text injected into the agent's context for this turn | + +**`postToolUse`** + +```json +{ + "timestamp": 1704614700000, + "cwd": "/path/to/project", + "toolName": "bash", + "toolArgs": "{\"command\":\"npm test\"}", + "toolResult": { + "resultType": "success", + "textResultForLlm": "All tests passed (15/15)" + } +} +``` + +`resultType` is `"success"`, `"failure"`, or `"denied"`. + +**`errorOccurred`** + +```json +{ + "timestamp": 1704614800000, + "cwd": "/path/to/project", + "error": { + "message": "Network timeout", + "name": "TimeoutError", + "stack": "TimeoutError: Network timeout\n at ..." + } +} +``` + +**`agentStop`** + +```json +{ + "timestamp": 1704618000000, + "cwd": "/path/to/project" +} +``` + +Minimal payload — use it to trigger end-of-session actions like running `git diff --stat` or final validation. + +## When Hooks Are the Wrong Tool + +| Avoid hooks for | Better fit | +| ---- | ---- | +| Open-ended reasoning or style guidance | Instructions, prompts, or agents | +| Long multi-step workflows with memory, retries, or branching | Agents, scripts, or workflow engines | +| Background daemons, watchers, debounce loops, or async jobs | Dedicated automation, services, or CI | +| Heavy repository-wide validation | CI, scheduled jobs, or dedicated automation | + +## Universal Design Rules + +| Rule | Why it matters | +| ---- | ---- | +| One hook, one responsibility | Small hooks are easier to trust and debug | +| Default to **observe first** | Blocking or mutation should be an explicit choice | +| Keep hooks synchronous, bounded, and non-interactive | Hooks run in the critical path | +| Make hooks deterministic and idempotent | Re-runs should not create drift | +| Do not mutate branch, index, or worktree state by default | Git-destructive behavior is high risk | +| Treat prompts, tool arguments, and tool output as untrusted and sensitive | Input may be hostile or private | +| Redact secrets, credentials, tokens, and private content from logs | Logs often outlive the hook run | + +## Script Authoring Rules + +- Validate the JSON fields you actually use +- Quote shell variables and never build commands from raw input +- Keep stdout clean unless the host requires structured output +- Use strict modes: Bash `set -euo pipefail`, PowerShell `Set-StrictMode -Version Latest` +- Check dependencies early and fail clearly if they are missing +- Avoid prompts, hidden installs, or environment mutation during execution +- Test scripts by piping representative JSON payloads into them manually + +## Choose the Smallest Viable Implementation + +1. **PowerShell 7**, **Node.js**, or **Python** for broadly portable hooks +2. **Bash** where Bash is an explicit requirement or safe assumption +3. **An existing project CLI** when the repository already depends on it + +Do **not** introduce a new compiled runtime just to implement an ordinary hook. + +## Packaging a Reusable Hook + +- Package config, scripts, and docs together +- Document the trigger event, purpose, side effects, dependencies, and disable path +- Explain what the hook reads, what it writes, and what it blocks + +## Anti-Patterns + +- Long-running hooks, watchers, background daemons, or fire-and-forget async work +- Heavy scans on every event when a narrower trigger would do +- Hidden network calls or uploads in the critical path +- Silent mutation of Git state (checkout, reset, clean, stash, stage, commit, push, or history rewriting) by default +- Interactive prompts or implicit approval steps +- Noisy stdout, ad-hoc output formats, or mixed machine/human output +- Logging raw prompts, secrets, credentials, or large tool outputs +- Monolithic hooks that mix unrelated responsibilities + +## Portability + +### GitHub Copilot: CLI, VS Code, and Cloud Agent + +The same `.github/hooks/*.json` config, the same payload schema, and the same script contract work across CLI, VS Code, and the cloud agent. Event names accept both camelCase (`preToolUse`) and PascalCase (`PreToolUse`). The documented payload field for tool arguments is `toolArgs` (a JSON string). + +One thing to know: the cloud agent only loads hooks from the repository's **default branch**. If your hooks.json is only on a feature branch, the cloud agent won't see it. + +### Claude Code + +Claude Code uses a different hook system: + +- Settings in `~/.claude/settings.json` and `.claude/settings.json` +- Different event names and matcher syntax (regex, `if` conditions) +- Exit 2 = block, exit 1 = non-blocking error (not the same as GitHub Copilot) +- 5 hook types (command, http, mcp_tool, prompt, agent) +- 29+ events including `FileChanged`, `CwdChanged`, `ConfigChange` + +The shared best practice is the same: keep hooks small, deterministic, explicit about I/O, and strict about side effects. diff --git a/.github/instructions/makefile.instructions.md b/.github/instructions/makefile.instructions.md new file mode 100644 index 0000000..45b5bad --- /dev/null +++ b/.github/instructions/makefile.instructions.md @@ -0,0 +1,410 @@ +--- +description: "Best practices for authoring GNU Make Makefiles" +applyTo: "**/Makefile, **/makefile, **/*.mk, **/GNUmakefile" +--- + +# Makefile Development Instructions + +Instructions for writing clean, maintainable, and portable GNU Make Makefiles. These instructions are based on the [GNU Make manual](https://www.gnu.org/software/make/manual/). + +## General Principles + +- Write clear and maintainable makefiles that follow GNU Make conventions +- Use descriptive target names that clearly indicate their purpose +- Keep the default goal (first target) as the most common build operation +- Prioritize readability over brevity when writing rules and recipes +- Add comments to explain complex rules, variables, or non-obvious behavior + +## Naming Conventions + +- Name your makefile `Makefile` (recommended for visibility) or `makefile` +- Use `GNUmakefile` only for GNU Make-specific features incompatible with other make implementations +- Use standard variable names: `objects`, `OBJECTS`, `objs`, `OBJS`, `obj`, or `OBJ` for object file lists +- Use uppercase for built-in variable names (e.g., `CC`, `CFLAGS`, `LDFLAGS`) +- Use descriptive target names that reflect their action (e.g., `clean`, `install`, `test`) + +## File Structure + +- Place the default goal (primary build target) as the first rule in the makefile +- Group related targets together logically +- Define variables at the top of the makefile before rules +- Use `.PHONY` to declare targets that don't represent files +- Structure makefiles with: variables, then rules, then phony targets + +```makefile +# Variables +CC = gcc +CFLAGS = -Wall -g +objects = main.o utils.o + +# Default goal +all: program + +# Rules +program: $(objects) + $(CC) -o program $(objects) + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +# Phony targets +.PHONY: clean all +clean: + rm -f program $(objects) +``` + +## Variables and Substitution + +- Use variables to avoid duplication and improve maintainability +- Define variables with `:=` (simple expansion) for immediate evaluation, `=` for recursive expansion +- Use `?=` to set default values that can be overridden +- Use `+=` to append to existing variables +- Reference variables with `$(VARIABLE)` not `$VARIABLE` (unless single character) +- Use automatic variables (`$@`, `$<`, `$^`, `$?`, `$*`) in recipes to make rules more generic + +```makefile +# Simple expansion (evaluates immediately) +CC := gcc + +# Recursive expansion (evaluates when used) +CFLAGS = -Wall $(EXTRA_FLAGS) + +# Conditional assignment +PREFIX ?= /usr/local + +# Append to variable +CFLAGS += -g +``` + +## Rules and Prerequisites + +- Separate targets, prerequisites, and recipes clearly +- Use implicit rules for standard compilations (e.g., `.c` to `.o`) +- List prerequisites in logical order (normal prerequisites before order-only) +- Use order-only prerequisites (after `|`) for directories and dependencies that shouldn't trigger rebuilds +- Include all actual dependencies to ensure correct rebuilds +- Avoid circular dependencies between targets +- Remember that order-only prerequisites are omitted from automatic variables like `$^`, so reference them explicitly if needed + +The example below shows a pattern rule that compiles objects into an `obj/` directory. The directory itself is listed as an order-only prerequisite so it is created before compiling but does not force recompilation when its timestamp changes. + +```makefile +# Normal prerequisites +program: main.o utils.o + $(CC) -o $@ $^ + +# Order-only prerequisites (directory creation) +obj/%.o: %.c | obj + $(CC) $(CFLAGS) -c $< -o $@ + +obj: + mkdir -p obj +``` + +## Recipes and Commands + +- Start every recipe line with a **tab character** (not spaces) unless `.RECIPEPREFIX` is changed +- Use `@` prefix to suppress command echoing when appropriate +- Use `-` prefix to ignore errors for specific commands (use sparingly) +- Combine related commands with `&&` or `;` on the same line when they must execute together +- Keep recipes readable; break long commands across multiple lines with backslash continuation +- Use shell conditionals and loops within recipes when needed + +```makefile +# Silent command +clean: + @echo "Cleaning up..." + @rm -f $(objects) + +# Ignore errors +.PHONY: clean-all +clean-all: + -rm -rf build/ + -rm -rf dist/ + +# Multi-line recipe with proper continuation +install: program + install -d $(PREFIX)/bin && \ + install -m 755 program $(PREFIX)/bin +``` + +## Phony Targets + +- Always declare phony targets with `.PHONY` to avoid conflicts with files of the same name +- Use phony targets for actions like `clean`, `install`, `test`, `all` +- Place phony target declarations near their rule definitions or at the end of the makefile + +```makefile +.PHONY: all clean test install + +all: program + +clean: + rm -f program $(objects) + +test: program + ./run-tests.sh + +install: program + install -m 755 program $(PREFIX)/bin +``` + +## Pattern Rules and Implicit Rules + +- Use pattern rules (`%.o: %.c`) for generic transformations +- Leverage built-in implicit rules when appropriate (GNU Make knows how to compile `.c` to `.o`) +- Override implicit rule variables (like `CC`, `CFLAGS`) rather than rewriting the rules +- Define custom pattern rules only when built-in rules are insufficient + +```makefile +# Use built-in implicit rules by setting variables +CC = gcc +CFLAGS = -Wall -O2 + +# Custom pattern rule for special cases +%.pdf: %.md + pandoc $< -o $@ +``` + +## Splitting Long Lines + +- Use backslash-newline (`\`) to split long lines for readability +- Be aware that backslash-newline is converted to a single space in non-recipe contexts +- In recipes, backslash-newline preserves the line continuation for the shell +- Avoid trailing whitespace after backslashes + +### Splitting Without Adding Whitespace + +If you need to split a line without adding whitespace, you can use a special technique: insert `$ ` (dollar-space) followed by a backslash-newline. The `$ ` refers to a variable with a single-space name, which doesn't exist and expands to nothing, effectively joining the lines without inserting a space. + +```makefile +# Concatenate strings without adding whitespace +# The following creates the value "oneword" +var := one$ \ + word + +# This is equivalent to: +# var := oneword +``` + +```makefile +# Variable definition split across lines +sources = main.c \ + utils.c \ + parser.c \ + handler.c + +# Recipe with long command +build: $(objects) + $(CC) -o program $(objects) \ + $(LDFLAGS) \ + -lm -lpthread +``` + +## Including Other Makefiles + +- Use `include` directive to share common definitions across makefiles +- Use `-include` (or `sinclude`) to include optional makefiles without errors +- Place `include` directives after variable definitions that may affect included files +- Use `include` for shared variables, pattern rules, or common targets + +```makefile +# Include common settings +include config.mk + +# Include optional local configuration +-include local.mk +``` + +## Conditional Directives + +- Use conditional directives (`ifeq`, `ifneq`, `ifdef`, `ifndef`) for platform or configuration-specific rules +- Place conditionals at the makefile level, not within recipes (use shell conditionals in recipes) +- Keep conditionals simple and well-documented + +```makefile +# Platform-specific settings +ifeq ($(OS),Windows_NT) + EXE_EXT = .exe +else + EXE_EXT = +endif + +program: main.o + $(CC) -o program$(EXE_EXT) main.o +``` + +## Automatic Prerequisites + +- Generate header dependencies automatically rather than maintaining them manually +- Use compiler flags like `-MMD` and `-MP` to generate `.d` files with dependencies +- Include generated dependency files with `-include $(deps)` to avoid errors if they don't exist + +```makefile +objects = main.o utils.o +deps = $(objects:.o=.d) + +# Include dependency files +-include $(deps) + +# Compile with automatic dependency generation +%.o: %.c + $(CC) $(CFLAGS) -MMD -MP -c $< -o $@ +``` + +## Error Handling and Debugging + +- Use `$(error text)` or `$(warning text)` functions for build-time diagnostics +- Test makefiles with `make -n` (dry run) to see commands without executing +- Use `make -p` to print the database of rules and variables for debugging +- Validate required variables and tools at the beginning of the makefile + +```makefile +# Check for required tools +ifeq ($(shell which gcc),) + $(error "gcc is not installed or not in PATH") +endif + +# Validate required variables +ifndef VERSION + $(error VERSION is not defined) +endif +``` + +## Clean Targets + +- Always provide a `clean` target to remove generated files +- Declare `clean` as phony to avoid conflicts with a file named "clean" +- Use `-` prefix with `rm` commands to ignore errors if files don't exist +- Consider separate `clean` (removes objects) and `distclean` (removes all generated files) targets + +```makefile +.PHONY: clean distclean + +clean: + -rm -f $(objects) + -rm -f $(deps) + +distclean: clean + -rm -f program config.mk +``` + +## Portability Considerations + +- Avoid GNU Make-specific features if portability to other make implementations is required +- Use standard shell commands (prefer POSIX shell constructs) +- Test with `make -B` to force rebuild all targets +- Document any platform-specific requirements or GNU Make extensions used + +## Performance Optimization + +- Use `:=` for variables that don't need recursive expansion (faster) +- Avoid unnecessary use of `$(shell ...)` which creates subprocesses +- Order prerequisites efficiently (most frequently changing files last) +- Use parallel builds (`make -j`) safely by ensuring targets don't conflict + +## Documentation and Comments + +- Add a header comment explaining the makefile's purpose +- Document non-obvious variable settings and their effects +- Include usage examples or targets in comments +- Add inline comments for complex rules or platform-specific workarounds + +```makefile +# Makefile for building the example application +# +# Usage: +# make - Build the program +# make clean - Remove generated files +# make install - Install to $(PREFIX) +# +# Variables: +# CC - C compiler (default: gcc) +# PREFIX - Installation prefix (default: /usr/local) + +# Compiler and flags +CC ?= gcc +CFLAGS = -Wall -Wextra -O2 + +# Installation directory +PREFIX ?= /usr/local +``` + +## Special Targets + +- Use `.PHONY` for non-file targets +- Use `.PRECIOUS` to preserve intermediate files +- Use `.INTERMEDIATE` to mark files as intermediate (automatically deleted) +- Use `.SECONDARY` to prevent deletion of intermediate files +- Use `.DELETE_ON_ERROR` to remove targets if recipe fails +- Use `.SILENT` to suppress echoing for all recipes (use sparingly) + +```makefile +# Don't delete intermediate files +.SECONDARY: + +# Delete targets if recipe fails +.DELETE_ON_ERROR: + +# Preserve specific files +.PRECIOUS: %.o +``` + +## Common Patterns + +### Standard Project Structure + +```makefile +CC = gcc +CFLAGS = -Wall -O2 +objects = main.o utils.o parser.o + +.PHONY: all clean install + +all: program + +program: $(objects) + $(CC) -o $@ $^ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + -rm -f program $(objects) + +install: program + install -d $(PREFIX)/bin + install -m 755 program $(PREFIX)/bin +``` + +### Managing Multiple Programs + +```makefile +programs = prog1 prog2 prog3 + +.PHONY: all clean + +all: $(programs) + +prog1: prog1.o common.o + $(CC) -o $@ $^ + +prog2: prog2.o common.o + $(CC) -o $@ $^ + +prog3: prog3.o + $(CC) -o $@ $^ + +clean: + -rm -f $(programs) *.o +``` + +## Anti-Patterns to Avoid + +- Don't start recipe lines with spaces instead of tabs +- Avoid hardcoding file lists when they can be generated with wildcards or functions +- Don't use `$(shell ls ...)` to get file lists (use `$(wildcard ...)` instead) +- Avoid complex shell scripts in recipes (move to separate script files) +- Don't forget to declare phony targets as `.PHONY` +- Avoid circular dependencies between targets +- Don't use recursive make (`$(MAKE) -C subdir`) unless absolutely necessary diff --git a/.github/instructions/qa-engineering-best-practices.instructions.md b/.github/instructions/qa-engineering-best-practices.instructions.md new file mode 100644 index 0000000..cdab69b --- /dev/null +++ b/.github/instructions/qa-engineering-best-practices.instructions.md @@ -0,0 +1,174 @@ +--- +applyTo: '**' +description: 'Comprehensive QA engineering best practices covering test strategy, test pyramid, naming conventions, assertion patterns, bug reporting, and automation guidelines for modern software projects.' +--- + +# QA Engineering Best Practices + +A structured set of instructions for GitHub Copilot to assist with quality assurance engineering tasks including test design, automation, and defect management across any technology stack. + +--- + +## Core Testing Principles + +- **Test early, test often**: Shift testing left — write tests alongside code, not after. +- **Test one thing at a time**: Each test case should verify a single behaviour or assertion. +- **Tests are first-class code**: Apply the same readability, naming, and refactoring standards to test code as to production code. +- **Fail fast**: Tests should produce clear, actionable failures that point directly to the broken behaviour. +- **Deterministic tests**: Tests must produce the same result on every run. Eliminate randomness, timing dependencies, and shared mutable state. +- **Independent tests**: No test should depend on another test's side effects. Tests must be runnable in any order. + +--- + +## Test Pyramid + +Follow the test pyramid to balance coverage, speed, and maintenance cost: + +| Layer | Scope | Quantity | Speed | +|-------|-------|----------|-------| +| Unit | Single function / class | Many (60–70 %) | Milliseconds | +| Integration | Module boundaries, DB, API contracts | Moderate (20–30 %) | Seconds | +| End-to-End | Full user journey across UI + backend | Few (5–10 %) | Minutes | + +- Prefer unit tests for business logic and edge cases. +- Use integration tests to validate contracts between services and external dependencies. +- Reserve end-to-end tests for critical user paths and smoke suites. + +--- + +## Test Naming Conventions + +Use the **Given / When / Then** (GWT) or **should_doX_whenY** pattern consistently. + +``` +// Good – describes scenario, action, expected result +test('should return 404 when product id does not exist') +test('given an expired token, when the user calls /me, then it returns 401') + +// Bad – vague, implementation-focused +test('test1') +test('check user') +``` + +- Group related tests in `describe` / `context` blocks named after the unit under test. +- Use `it` or `test` for individual cases. +- Test names must be readable as standalone sentences. + +--- + +## Assertion Best Practices + +- **One logical assertion per test** where practical; avoid asserting multiple unrelated things. +- Use **specific matchers** over equality checks (`toContain`, `toBeGreaterThan`, `toMatchObject`). +- Always assert the **exact expected value**, not just truthiness (`expect(result).toBe(42)` not `expect(result).toBeTruthy()`). +- For exception testing, assert both the exception type and message. +- Prefer **positive assertions** over negative ones when testing the happy path. + +```typescript +// Good +expect(response.status).toBe(200); +expect(response.body.items).toHaveLength(3); + +// Avoid +expect(response).toBeTruthy(); +expect(response.body).not.toBeNull(); +``` + +--- + +## Test Data Management + +- Use **factories or builders** to create test data — avoid hardcoding raw objects in every test. +- Keep test data **minimal**: only include fields relevant to the test. +- Use **unique identifiers** per test run to avoid collision in shared environments. +- Never use production data or PII in tests. +- Reset or isolate state between tests (in-memory DB, transactions rolled back, mocked dependencies). + +--- + +## Mocking and Stubbing Guidelines + +- Mock **at the boundary** (HTTP clients, DB adapters, message queues) — not deep inside business logic. +- Prefer **real implementations** for pure functions and simple value objects. +- Stubs return controlled data; mocks additionally verify interactions — choose the right tool. +- Reset all mocks between tests to prevent state leakage. +- Document why a dependency is mocked if the reason is non-obvious. + +--- + +## API Testing + +- Validate **status code**, **response schema**, **headers**, and **response time** for every endpoint. +- Test all **HTTP methods** the endpoint exposes (GET, POST, PUT, PATCH, DELETE). +- Cover **authentication and authorisation** paths: valid token, expired token, missing token, wrong role. +- Test **boundary values** for inputs: empty string, null, max length, special characters, Unicode. +- Validate **error response bodies** follow a consistent schema. +- Assert **idempotency** for PUT and DELETE operations. + +--- + +## UI / End-to-End Testing + +- Target **user-visible behaviour**, not implementation details (avoid asserting CSS classes or internal state). +- Use **accessible selectors** in order of preference: `role` → `label` → `test-id` → `text`. +- Avoid `sleep` / fixed waits; use **explicit waits** on element state (visible, enabled, network idle). +- Run E2E tests against a **stable, isolated environment** (not shared staging). +- Keep E2E scenarios **short and focused** — break long flows into smaller composable steps. +- Capture **screenshots and traces** on failure for easier debugging. + +--- + +## Performance Testing + +- Define **SLOs** (Service Level Objectives) before writing performance tests: target latency p50/p95/p99, throughput, error rate. +- Include **ramp-up**, **steady state**, and **ramp-down** phases in load tests. +- Test under **realistic data volumes** — synthetic tests with empty DBs are not representative. +- Track results over time to detect **performance regressions**. +- Distinguish between **load testing** (expected traffic), **stress testing** (beyond capacity), and **soak testing** (sustained load over time). + +--- + +## Bug Reporting Standards + +A good bug report includes: + +1. **Title**: concise, specific — include component, action, and symptom (`[Checkout] Order total is incorrect when coupon is applied`). +2. **Environment**: OS, browser/runtime version, deployment environment. +3. **Steps to reproduce**: numbered, minimal, deterministic. +4. **Expected result**: what should happen. +5. **Actual result**: what actually happens, including error messages and stack traces. +6. **Severity**: Critical / High / Medium / Low (defined by business impact). +7. **Attachments**: screenshots, logs, network traces, test IDs. + +--- + +## Test Coverage Guidelines + +- Aim for **meaningful coverage**, not a percentage target — 100 % line coverage with trivial tests is worthless. +- Prioritise coverage for **critical paths**, **complex logic**, and **previously buggy areas**. +- Track **branch coverage** and **mutation scores** alongside line coverage. +- Use coverage reports to find untested **edge cases**, not to game metrics. + +--- + +## CI/CD Integration + +- Tests must pass in CI before any merge to main/trunk — no exceptions. +- Run **fast tests** (unit, lint) on every commit; run **slow tests** (integration, E2E) on PR merge or nightly. +- Make test failures **visible and actionable** in CI output — include test name, failure reason, and relevant logs. +- Archive **test reports and artefacts** (JUnit XML, coverage HTML, traces) as CI build artefacts. +- Configure **flaky test detection**: auto-retry once, flag as flaky after repeated inconsistency. + +--- + +## Test Review Checklist + +Before approving a PR that changes tests: + +- [ ] New behaviour is covered by tests at the appropriate pyramid level. +- [ ] Tests are named clearly and follow the project convention. +- [ ] No `sleep`, `Thread.Sleep`, or arbitrary timeouts. +- [ ] Mocks are reset after each test. +- [ ] No hardcoded environment-specific values (URLs, credentials). +- [ ] Tests are independent and can run in isolation. +- [ ] Test code is readable without needing to read the implementation. diff --git a/.github/instructions/self-explanatory-code-commenting.instructions.md b/.github/instructions/self-explanatory-code-commenting.instructions.md new file mode 100644 index 0000000..5ffa68f --- /dev/null +++ b/.github/instructions/self-explanatory-code-commenting.instructions.md @@ -0,0 +1,162 @@ +--- +description: 'Guidelines for GitHub Copilot to write comments to achieve self-explanatory code with less comments. Examples are in JavaScript but it should work on any language that has comments.' +applyTo: '**' +--- + +# Self-explanatory Code Commenting Instructions + +## Core Principle +**Write code that speaks for itself. Comment only when necessary to explain WHY, not WHAT.** +We do not need comments most of the time. + +## Commenting Guidelines + +### ❌ AVOID These Comment Types + +**Obvious Comments** +```javascript +// Bad: States the obvious +let counter = 0; // Initialize counter to zero +counter++; // Increment counter by one +``` + +**Redundant Comments** +```javascript +// Bad: Comment repeats the code +function getUserName() { + return user.name; // Return the user's name +} +``` + +**Outdated Comments** +```javascript +// Bad: Comment doesn't match the code +// Calculate tax at 5% rate +const tax = price * 0.08; // Actually 8% +``` + +### ✅ WRITE These Comment Types + +**Complex Business Logic** +```javascript +// Good: Explains WHY this specific calculation +// Apply progressive tax brackets: 10% up to 10k, 20% above +const tax = calculateProgressiveTax(income, [0.10, 0.20], [10000]); +``` + +**Non-obvious Algorithms** +```javascript +// Good: Explains the algorithm choice +// Using Floyd-Warshall for all-pairs shortest paths +// because we need distances between all nodes +for (let k = 0; k < vertices; k++) { + for (let i = 0; i < vertices; i++) { + for (let j = 0; j < vertices; j++) { + // ... implementation + } + } +} +``` + +**Regex Patterns** +```javascript +// Good: Explains what the regex matches +// Match email format: username@domain.extension +const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; +``` + +**API Constraints or Gotchas** +```javascript +// Good: Explains external constraint +// GitHub API rate limit: 5000 requests/hour for authenticated users +await rateLimiter.wait(); +const response = await fetch(githubApiUrl); +``` + +## Decision Framework + +Before writing a comment, ask: +1. **Is the code self-explanatory?** → No comment needed +2. **Would a better variable/function name eliminate the need?** → Refactor instead +3. **Does this explain WHY, not WHAT?** → Good comment +4. **Will this help future maintainers?** → Good comment + +## Special Cases for Comments + +### Public APIs +```javascript +/** + * Calculate compound interest using the standard formula. + * + * @param {number} principal - Initial amount invested + * @param {number} rate - Annual interest rate (as decimal, e.g., 0.05 for 5%) + * @param {number} time - Time period in years + * @param {number} compoundFrequency - How many times per year interest compounds (default: 1) + * @returns {number} Final amount after compound interest + */ +function calculateCompoundInterest(principal, rate, time, compoundFrequency = 1) { + // ... implementation +} +``` + +### Configuration and Constants +```javascript +// Good: Explains the source or reasoning +const MAX_RETRIES = 3; // Based on network reliability studies +const API_TIMEOUT = 5000; // AWS Lambda timeout is 15s, leaving buffer +``` + +### Annotations +```javascript +// TODO: Replace with proper user authentication after security review +// FIXME: Memory leak in production - investigate connection pooling +// HACK: Workaround for bug in library v2.1.0 - remove after upgrade +// NOTE: This implementation assumes UTC timezone for all calculations +// WARNING: This function modifies the original array instead of creating a copy +// PERF: Consider caching this result if called frequently in hot path +// SECURITY: Validate input to prevent SQL injection before using in query +// BUG: Edge case failure when array is empty - needs investigation +// REFACTOR: Extract this logic into separate utility function for reusability +// DEPRECATED: Use newApiFunction() instead - this will be removed in v3.0 +``` + +## Anti-Patterns to Avoid + +### Dead Code Comments +```javascript +// Bad: Don't comment out code +// const oldFunction = () => { ... }; +const newFunction = () => { ... }; +``` + +### Changelog Comments +```javascript +// Bad: Don't maintain history in comments +// Modified by John on 2023-01-15 +// Fixed bug reported by Sarah on 2023-02-03 +function processData() { + // ... implementation +} +``` + +### Divider Comments +```javascript +// Bad: Don't use decorative comments +//===================================== +// UTILITY FUNCTIONS +//===================================== +``` + +## Quality Checklist + +Before committing, ensure your comments: +- [ ] Explain WHY, not WHAT +- [ ] Are grammatically correct and clear +- [ ] Will remain accurate as code evolves +- [ ] Add genuine value to code understanding +- [ ] Are placed appropriately (above the code they describe) +- [ ] Use proper spelling and professional language + +## Summary + +Remember: **The best comment is the one you don't need to write because the code is self-documenting.** diff --git a/.github/skills/ai-ready/SKILL.md b/.github/skills/ai-ready/SKILL.md new file mode 100644 index 0000000..ee62a69 --- /dev/null +++ b/.github/skills/ai-ready/SKILL.md @@ -0,0 +1,243 @@ +--- +name: ai-ready +license: MIT +metadata: + version: "1.1.0" +description: "**ANALYSIS SKILL** — Analyze any repository and generate AI-ready configuration — AGENTS.md, copilot-instructions.md, skills, CI workflows, issue templates. WHEN: \"make this repo ai-ready\", \"set up AI config\", \"add copilot instructions\", \"prepare this repo for AI contributions\", \"generate AGENTS.md\". INVOKES: glob, grep, view, create, edit for repo analysis and file generation. FOR SINGLE OPERATIONS: use create/edit directly for individual config files." +--- + +# AI-Ready Repo Skill + +## Persona + +Adopt the perspective of an experienced repo maintainer who has managed high-traffic repos and reviewed thousands of PRs. Prioritize what **reduces review burden and contributor friction**. Every file you generate should earn its place — generic boilerplate creates noise. + +--- + +Follow these steps in order to analyze the current repository and generate all missing AI-ready configuration assets. + +**First run vs. re-run:** On the first run, most assets will be missing — the skill creates them. On re-runs, it **audits** existing assets against the current codebase, checking for drift, stale content, and new conventions from recent PR reviews. The skill **never overwrites existing files without user approval**. + +**Skipping assets:** If the user's prompt mentions skipping specific assets (e.g., "skip CI and issue templates"), respect those exclusions. Still run the full analysis, but skip generation for the excluded assets. + +**Report-only mode:** If the user asks for a report without generating files (e.g., "how ai-ready is this repo?", "score this repo"), run the full analysis (Steps 0–1) and display the report (Step 11) — but skip all generation steps (Steps 2–10). + +### The 12 tracked assets + +Assets are grouped into three categories. Count assets with **Nailed It** status for the score. + +**🤖 AI Context** — what AI agents read to understand your repo + +| # | Asset | Generated in | +|---|-------|-------------| +| 1 | `AGENTS.md` | Step 2 | +| 2 | `.github/copilot-instructions.md` | Step 3 | +| 3 | Maintenance matrix (in `copilot-instructions.md`) | Step 8 | +| 4 | `.mcp.json` | Step 4b | +| 5 | `.github/workflows/copilot-setup-steps.yml` | Step 4 | + +**🔧 Dev Workflow** — what keeps PRs clean and contributors on track + +| # | Asset | Generated in | +|---|-------|-------------| +| 6 | CI workflow (`.github/workflows/ci.yml`) | Step 5 | +| 7 | Issue templates (`.github/ISSUE_TEMPLATE/`) | Step 6 | +| 8 | PR template (`.github/PULL_REQUEST_TEMPLATE.md`) | Step 6 | +| 9 | `.github/dependabot.yml` | (checked, not generated) | + +**📖 Onboarding** — what helps new contributors get started + +| # | Asset | Generated in | +|---|-------|-------------| +| 10 | README Contributing section | Step 7 | +| 11 | Changelog (`CHANGELOG.md`) | Step 9 | +| 12 | Documentation (or explicit "not needed" note) | Step 10 | + +**Scoring:** 🟩 Nailed It (counted) · 🟨 Could Be Better (not counted) · ⬜ Missing (not counted) + +| Medal | Name | Count | What it means | +|-------|------|-------|---------------| +| 🥉 | **Getting Started** | 1–4 | Basics in place but AI agents are mostly guessing | +| 🥈 | **On Track** | 5–7 | AI agents can help but miss your conventions | +| 🥇 | **Solid** | 8–10 | AI agents follow your patterns and catch most expectations | +| 🏆 | **AI-Ready** | 11–12 | AI agents contribute like your best team members | + +--- + +## Step 0 — Detect GitHub context automatically + +**Zero user input required.** The skill is GitHub-native — it discovers everything from GitHub's tools. + +### 0a. Identify the repo + +Run `git remote -v` to extract the GitHub `owner/repo`. If not GitHub, fall back to local-only analysis. + +### 0b–0d. Fetch metadata, mine PR reviews, check community health + +Use GitHub MCP tools or `gh` CLI to auto-discover repo metadata, PR review patterns, and community health gaps. See [references/github-discovery.md](references/github-discovery.md) for the full API table, PR mining technique, and health gap mapping. + +Key insight: **PR review mining is the highest-value step.** Repeated reviewer feedback becomes conventions in `copilot-instructions.md`. + +--- + +## Step 1 — Analyze the codebase + +GitHub context tells you *what* the repo is. Local analysis tells you *how* it works. Use glob, grep, and view combined with GitHub context from Step 0. + +### 1a. Detect languages, frameworks, and repo type + +Find manifest files and extract details. See [references/detection-tables.md](references/detection-tables.md) for the full manifest table, VS Code extension detection, multi-app collections, demo app patterns, and course/tutorial repo detection. + +Key detections: lockfiles, runtime version files, monorepo markers, notebooks, VS Code extensions, multi-app collections, demo apps. + +**Course repos** (3+ signals: numbered folders, lesson keywords, no primary app) adapt Steps 2–5. See detection-tables.md for the full signal list and step adaptations. + +### 1b. Detect test setup + +Identify test runner, find test directories (`tests/`, `__tests__/`, `spec/`, `e2e/`), extract test commands from scripts. + +### 1c. Detect CI/CD + +Check `.github/workflows/` for PR triggers. Check for other CI systems. Recognize community workflows (stale, welcome) as valid automation — not missing CI. + +### 1d. Check existing AI configuration + +Check for: `AGENTS.md`, `.github/copilot-instructions.md`, `.github/skills/`, `.github/agents/`, `.github/extensions/`, `.devcontainer/`. + +**copilot-setup-steps.yml** — check ALL known locations: `.github/workflows/copilot-setup-steps.yml` (canonical), `.github/copilot-setup-steps.yml` (legacy), and repo root. If found in a non-canonical location, flag it for consolidation into `.github/workflows/` — do not create a duplicate. + +If multiple instruction files exist, check for duplicates, contradictions, stale references, and scope clarity. See [references/detection-tables.md](references/detection-tables.md) for drift detection details. + +### 1e. Check repo configuration + +Check for: `CODEOWNERS`, `dependabot.yml`, issue templates, PR template, `LICENSE`, README Contributing section. + +### 1f–1g. Evaluate changelog and documentation + +Assess changelog health (exists, format, freshness). Assess docs (exists, framework, navigation, deploy pipeline, README linkage). + +### 1h. Scan directory structure + +List top-level directories and immediate children (skip `node_modules`, `.git`, `dist`, `build`, `target`, `vendor`). + +### 1i. Compile findings + +Produce a structured findings table combining GitHub context and codebase analysis with file-path evidence. See [references/detection-tables.md](references/detection-tables.md) for the full findings table template. + +List which of the 12 assets are missing. For existing assets, compare against analysis and flag drift as "Could Be Better." + +### 1j. Detect monorepo areas + +If workspace config found, list areas with name, path glob, and primary stack. For large library monorepos, map cross-package dependencies. See [references/detection-tables.md](references/detection-tables.md) for details. + +--- + +## Step 2 — Generate AGENTS.md + +If missing, create `AGENTS.md` at the repo root. If it exists, compare against analysis and flag drift. **Do not overwrite.** + +Sections: Project Overview (never hardcode versions — reference manifests), Repository Structure, Tech Stack, Build & Run, Testing, Key Patterns and Conventions, CI/CD, Adding a New [Feature/Module] (trace the full registration chain — enums, index re-exports, config declarations), Screen Size / Responsive Rules (UI projects only), Common Pitfalls. + +--- + +## Step 3 — Generate .github/copilot-instructions.md + +If missing, create it. If it exists, compare against analysis — especially new PR review patterns and maintenance matrix drift. + +Content: Language-Specific Conventions (separate subsections for multi-language repos), Notebook Conventions (if `.ipynb` detected), Course/Lesson Conventions (if course repo), Framework Patterns, Conventions Mined from PR Reviews, Test Conventions, Code Style Notes (reference linter configs), Asset/Content Rules (if assets detected), **Maintenance Matrix** (trace dependency graphs — the most valuable section). + +The maintenance matrix defines what must be updated when different parts of the codebase change. Populate with real file paths. Trace import chains and registration patterns — don't stop at top-level files. + +**Monorepo:** Create `.github/instructions/{area-name}.instructions.md` with `applyTo` patterns for areas with different stacks. + +--- + +## Step 4 — Generate copilot-setup-steps.yml + +Check ALL locations first: `.github/workflows/copilot-setup-steps.yml`, `.github/copilot-setup-steps.yml`, and repo root. If one exists anywhere, do NOT create another — consolidate into `.github/workflows/` if at a legacy location. + +If truly missing from all locations, create `.github/workflows/copilot-setup-steps.yml`. Steps: checkout, set up runtime, install dependencies, install test dependencies, build. Derive from existing CI when possible. For .NET multi-target, install all required SDK versions. + +--- + +## Step 4b — Generate .mcp.json + +If missing, generate `.mcp.json` at the repo root based on detected dependencies (databases, APIs, cloud platforms, browser automation, DevOps tools). Use `${VAR}` for secrets. Only include servers the project actually needs — do not speculatively add servers. + +*Why?*: Copilot CLI no longer supports `.vscode/mcp.json` — the correct location is `.mcp.json` at the repo root. If `.vscode/mcp.json` exists, flag it as "Could Be Better" and suggest migrating to `.mcp.json`. + +--- + +## Step 5 — Generate CI workflow + +If no PR-triggered workflow exists, create `.github/workflows/ci.yml` with: `pull_request` + `push` triggers with `paths-ignore` for docs/config, a build-and-test job matching the project's actual toolchain. Use the **default branch** detected in Step 0b — do not hardcode `main`. Never modify existing workflows. + +--- + +## Step 6 — Generate issue templates and PR template + +If missing, create bug report and feature request YAML forms, plus a PR template with description, changes, how-to-test, and checklist (derived from maintenance matrix). Note old-format `.md` templates as "Could Be Better." + +--- + +## Step 7 — Update README Contributing section + +If README exists but has no Contributing section: link to `CONTRIBUTING.md` if it exists, otherwise add a Contributing section with fork/branch/PR instructions and test commands. Never rewrite the rest of the README. + +--- + +## Step 8 — Verify maintenance matrix + +Verify the matrix in `copilot-instructions.md` covers file cross-references, change cascades, and cross-cutting concerns. Trace actual dependency graphs per language (`.csproj` ProjectReferences, import chains, `mod` declarations, `__init__.py` re-exports). + +--- + +## Step 9 — Evaluate and improve changelog + +If missing, create `CHANGELOG.md` with Keep a Changelog format. If a pointer file, verify the target. If stale, flag with dates. Document non-standard locations in AGENTS.md. + +--- + +## Step 10 — Evaluate and improve documentation + +If docs exist, add to AGENTS.md and copilot-instructions.md. If missing, assess whether needed by project type. Always document docs status in AGENTS.md. + +--- + +## Step 11 — Display the AI-Readiness Report + +Display the report using the format in [references/report-template.md](references/report-template.md). Include the skill version from frontmatter `metadata.version` at the bottom of the report (e.g., `Generated by ai-ready v1.0.0`). Then: +1. Add AI-Ready badge (see report-template.md § 11a) +2. Offer to create PR (see report-template.md § 11b) + +--- + +## Important Rules + +### Do No Harm + +This skill's first obligation is to leave the repo in a **better state than it found it — never worse**. Every rule below serves this principle. + +- **NEVER create duplicates** — before creating any file, check ALL known locations (canonical, legacy, and root). If a file exists anywhere, do not create another copy. Consolidate instead. +- **NEVER push directly to main/master** — always create a feature branch and open a PR for review. The only exception is if the user explicitly asks to commit to the default branch. +- **NEVER overwrite existing files** — only create missing assets. Flag drift for user review. +- **NEVER delete files without user approval** — if consolidating duplicates or removing stale files, include the deletion in the PR for review. + +### General Rules + +- **NEVER open a pager** — append `| cat` to every `gh`/`git` command. Use `git --no-pager`. +- **ALWAYS customize to the repo's actual stack** — never produce generic boilerplate. +- **Self-consistency** — every generated file must follow the conventions you establish. Cross-check before finalizing. +- **GitHub-native by default** — auto-discover via MCP tools and `gh` CLI. Fall back to local analysis. +- **Mine PR reviews** — turn repeated review feedback into `copilot-instructions.md` rules. +- **Be specific** — real file paths, real commands, real patterns. +- **Use `create` to write new files** — never `edit` from scratch. +- **Run full analysis first (Steps 0–1)** — never guess. +- **ALWAYS display the report at the end** — never skip or abbreviate. +- **NEVER use markdown headings in user output** — use bold + emojis instead. + +--- + +## Training Repos + +See [references/training-repos.md](references/training-repos.md) for the full list of repos used to validate this skill's heuristics. diff --git a/.github/skills/ai-ready/references/detection-tables.md b/.github/skills/ai-ready/references/detection-tables.md new file mode 100644 index 0000000..38dd2b2 --- /dev/null +++ b/.github/skills/ai-ready/references/detection-tables.md @@ -0,0 +1,137 @@ +# Detection Tables Reference + +Detailed detection heuristics for Step 1 — codebase analysis. + +## Manifest detection + +| Manifest | Language | What to extract | +|----------|----------|-----------------| +| `package.json` | JavaScript/TypeScript | dependencies, devDependencies, scripts (build, test, lint, typecheck), engines.node | +| `Cargo.toml` | Rust | workspace members, dependencies, build/test profile | +| `go.mod` | Go | module name, Go version | +| `pyproject.toml` or `requirements.txt` | Python | dependencies, build system, scripts, python version | +| `*.csproj` or `*.sln` | C# / .NET | target framework, package references, test SDK | +| `Gemfile` | Ruby | dependencies, ruby version | +| `pom.xml` or `build.gradle` | Java | dependencies, plugins, build tasks | + +Also check for: +- **Lockfiles** — `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`, `bun.lockb`, `Cargo.lock`, `go.sum`, `poetry.lock`, `Pipfile.lock` +- **Runtime version files** — `.nvmrc`, `.node-version`, `.python-version`, `.tool-versions`, `.ruby-version`, `rust-toolchain.toml` +- **Monorepo markers** — `pnpm-workspace.yaml`, `lerna.json`, `nx.json`, `turbo.json`, Cargo workspace, Go workspace. Also check for **large library monorepos**: Maven aggregator (`pom.xml` with ``), Python multi-package (`libs/` directory with multiple `pyproject.toml`), or Turborepo + Changesets (`turbo.json` + `.changeset/`). + + *Why?*: Large open-source libraries like LangChain organize code as multi-package monorepos — dozens of independently published packages under one repo. Treating them as a single package misses cross-package dependencies, per-package build commands, and module-specific conventions. +- **Notebooks** — `*.ipynb` files. If found, note the count and locations. Notebooks are common in course repos, data science projects, and tutorials. + +## VS Code extension detection + +Check for `contributes` in root `package.json` (commands, themes, snippets, views, menus). If present, this is a **VS Code extension**, not a regular app. Also check for `vsce` or `@vscode/vsce` in devDependencies, and `vscode:prepublish` in scripts. Extensions come in three flavors: +- **Functional extensions** — TypeScript code with activation events, commands, webpack/esbuild bundling, tests +- **Theme extensions** — JSON theme files, no runtime code, published via `vsce` +- **Snippet extensions** — JSON snippet definitions, language-scoped, content-driven not logic-driven + +*Why?*: VS Code extensions look like npm packages but have completely different conventions. The `package.json` IS the product spec — commands, menus, settings, keybindings. Treating them like a web app misses what matters. + +## Multi-app collection detection + +Multiple independent apps in subdirectories (e.g., `angular/`, `react/`, `svelte/`), each with its own `package.json`, but **no workspace config** tying them together. This is different from a monorepo — there's no shared build or dependency graph. Each app builds and runs independently. + +*Why?*: Not every repo with multiple folders is a monorepo. Some are "collections" — the same concept implemented in different frameworks for comparison or learning. Don't invent workspace tooling where none exists. + +## Demo app pattern detection + +A frontend app + mock backend (`json-server`, `db.json`) + proxy config (`proxy.conf.json`, `vite.config.ts` proxy). Common in demo/tutorial repos. If detected, document the mock API setup in AGENTS.md so agents know to start both frontend and backend. + +## Course/tutorial repo detection + +*Why?*: Course repos are fundamentally different from application repos. The "product" is markdown lessons and code samples — not a running application. Generating CI, setup steps, or a build pipeline for a course repo misses the point. Detecting this early shapes every later step. + +Check for **multiple signals** — no single check is definitive: + +1. **Numbered folders** — glob for top-level directories matching `NN-*` (e.g., `00-intro`, `01-setup`, `05-advanced`), `N-topic` (e.g., `1-Introduction`, `6-Data-Science-In-Wild`), `Chapter N`, `Module N`, or `Unit N`. 3+ matches is a strong signal. +2. **README content** — scan the root README for course/tutorial language: "lesson", "chapter", "module", "unit", "what you'll learn", "prerequisites", "course structure", "hands-on", "assignment", "quiz", "curriculum", "week". Multiple matches strengthen the signal. +3. **Repo description/topics** — check the GitHub description and topics (from Step 0b) for terms like "beginners", "course", "tutorial", "workshop", "learn", "curriculum", "lessons". +4. **Lesson structure** — check if numbered folders each contain a `README.md` (lesson content) and optionally `assignment.md`, `solution/`, `code/`, `quiz/`, or `notebook/` subdirectories. +5. **No primary application** — the repo has no root-level `package.json`, `Cargo.toml`, `go.mod`, or other manifest that would indicate a buildable application (individual lesson folders may have their own manifests for code samples). +6. **Devcontainer** — check for `.devcontainer/` directory. Common in course repos to provide a ready-to-go development environment. If present, credit it as a form of environment setup (similar to copilot-setup-steps.yml). + +**A repo is a course if 3+ of these signals are present.** Record it in the findings table as `Repo type: course` with evidence. + +### Course repo adaptations + +When a repo is a course, the following steps adapt: +- **Step 4** (copilot-setup-steps.yml) — skip if a `.devcontainer/` exists (it serves the same purpose for courses). If no devcontainer and no build step, skip entirely. +- **Step 5** (CI workflow) — skip build/test CI. Suggest markdown validation (link checking, spell check) instead if not already present. +- **Step 3** (copilot-instructions.md) — include lesson structure conventions: expected folder contents, naming patterns, how to add a new lesson. If lessons have quizzes or assignments, document the expected structure (e.g., each lesson needs `README.md` + `assignment.md` + `solution/`). +- **Step 2** (AGENTS.md) — "Adding a New Lesson" section instead of "Adding a New Feature". Include the lesson template (what files/folders each lesson should contain). +- **Report** — mark skipped assets as "N/A — course repo" instead of "Missing". Credit `.devcontainer/` in the "Nailed It" section if present. + +## Findings table template + +Before proceeding from Step 1, produce a structured summary combining GitHub context (Step 0) and codebase analysis (Step 1). Include file-path evidence for each finding: + +| Category | Finding | Evidence (source) | +|----------|---------|-------------------| +| Repo | e.g., johnpapa/ai-ready | `git remote -v` | +| Description | e.g., "Copilot CLI skill..." | GitHub API / repo metadata | +| Topics | e.g., copilot, skills, ai-ready | GitHub API | +| Language | e.g., TypeScript (65%), Rust (30%) | GitHub API language breakdown | +| Multi-language | yes/no — if no single language exceeds 50%, flag as multi-language | GitHub API | +| Repo type | app / course / docs-only / VS Code extension / npm package / collection | Step 1a-ii detection | +| VS Code extension type | functional / theme / snippets (if applicable) | `package.json` contributes field | +| Notebooks | e.g., 12 `.ipynb` files in `lessons/` | glob for `*.ipynb` | +| Mock backend | e.g., json-server on port 3000 | `db.json`, proxy config | +| Framework | e.g., React, Phaser | `package.json` dependencies | +| Test runner | e.g., Vitest | `package.json` devDependencies | +| Test command | e.g., `npm test` | `package.json` scripts.test | +| Build command | e.g., `npm run build` | `package.json` scripts.build | +| Runtime version | e.g., Node 22 | `.nvmrc` or `package.json` engines | +| Package manager | e.g., pnpm | `pnpm-lock.yaml` exists | +| Contributors | e.g., 3 contributors | GitHub API | +| Team size | e.g., solo / small / large | Contributor count | +| PR CI exists | yes/no | `.github/workflows/` or GitHub Actions API | +| Community health | e.g., 71% | GitHub API community/profile | +| PR review patterns | e.g., "maintainer often asks for tests" | Mined from recent PR review comments | +| Release cadence | e.g., monthly, tagged releases | GitHub Releases API | +| AGENTS.md | exists / missing | repo root | +| copilot-instructions.md | exists / missing | `.github/` | +| Changelog | exists / pointer / missing | `CHANGELOG.md`, Releases | +| Changelog freshness | current / stale | latest entry vs latest git tag | +| Docs exist | yes / no | `docs/`, config file | +| Docs framework | Docsify / Docusaurus / etc. | config file path | +| Docs deploy pipeline | yes / no | workflow file path | +| README links to docs | yes / no | README.md link | +| Default branch | e.g., `main`, `dev`, `master` | `gh repo view --json defaultBranchRef` | +| Push access | yes / no | `gh api repos/{owner}/{repo} --jq '.permissions.push'` | +| Custom agents | e.g., 2 agents: migration guide, orchestrator | `.github/agents/` | +| Custom skills | e.g., 6 skills: bunit-test, component-dev, ... | `.github/skills/` | +| Devcontainer | yes/no | `.devcontainer/` | +| Monorepo | yes/no | workspace config file | +| Areas | e.g., frontend (React), backend (Express), shared (TypeScript) | workspace config paths | + +## Drift detection for existing assets + +For existing AI-ready assets, read their current contents and compare against your analysis. Flag drift in any of these dimensions: + +| Asset | What to compare | +|-------|----------------| +| `AGENTS.md` | Repo structure still accurate? Build/test commands still correct? Tech stack changed? | +| `copilot-instructions.md` | New conventions from recent PR reviews? Maintenance matrix still covers current file relationships? | +| `copilot-setup-steps.yml` | Runtime versions match? Install/build commands still correct? New dependencies? | +| CI workflow | Build/test/lint commands still match the project? New tools added? | +| Issue templates | Still relevant to the project type? | +| README Contributing | Links still valid? Commands still correct? | + +For each existing asset where you find drift, classify it as **"Could Be Better"** in the report with a specific suggestion (e.g., "AGENTS.md lists Node 18 but `.nvmrc` now says Node 22"). Do not silently skip existing files — always evaluate them. + +## Monorepo area detection + +If a workspace config was found in Step 1a, read it to find package/project paths (e.g., `packages/*`, `apps/*`, `libs/*`). List each area — name, path glob, and primary stack — and note which areas have conventions that differ from root. + +**For large library monorepos** (Maven aggregator, Python `libs/`, pnpm workspace with many packages): +- List each published package/module separately with its purpose (e.g., `langchain4j-core`, `langchain4j-open-ai`, `langchain4j-ollama`) +- Note the module taxonomy if one exists (core vs providers vs integrations vs experimental) +- Identify **cross-package dependencies** — which packages depend on which. Changes to core packages ripple to all dependents. +- Detect **release tooling** — Changesets (`.changeset/`), semantic-release, Maven release plugin, or manual versioning. Document in the maintenance matrix. +- Detect **conditional modules** — JDK-specific modules (`jdk21`), platform-specific builds, or optional integrations that only build under certain conditions. + +*Why?*: A fix in `langchain4j-core` affects 30+ downstream modules. Without mapping cross-package dependencies, agents make changes to one package and miss the ripple effects. diff --git a/.github/skills/ai-ready/references/github-discovery.md b/.github/skills/ai-ready/references/github-discovery.md new file mode 100644 index 0000000..71cc2f8 --- /dev/null +++ b/.github/skills/ai-ready/references/github-discovery.md @@ -0,0 +1,52 @@ +# GitHub Discovery Reference + +Detailed API calls and techniques for Step 0 — GitHub-native context discovery. + +## 0b. Fetch repo metadata from GitHub + +Use the GitHub MCP tools (if available) or `gh` CLI to pull rich context the user should never have to explain: + +| What to fetch | Tool / Command | What you learn | +|---------------|---------------|----------------| +| Repo description, topics, visibility, default branch | `github-mcp-server-get_file_contents` on `/` or `gh repo view --json description,topics,isPrivate,primaryLanguage,defaultBranchRef --jq '.' | cat` | What this project is about, how it's categorized, default branch name | +| Language breakdown | `gh api repos/{owner}/{repo}/languages | cat` (bash) | Accurate language percentages (better than guessing from files) | +| Community health | `gh api repos/{owner}/{repo}/community/profile | cat` (bash) | Which community files exist (CONTRIBUTING, CODE_OF_CONDUCT, license, issue templates) — GitHub already knows this | +| Contributors | `gh api repos/{owner}/{repo}/contributors --jq '.[].login' | cat` (bash) | Team size, contribution patterns | +| Open issues | `github-mcp-server-list_issues` or `gh issue list | cat` | Active problems, what the project cares about | +| Recent merged PRs | `gh pr list --state merged --limit 10 --json title,body,files | cat` (bash) | Contribution patterns — what files get touched together, what a typical PR looks like | +| PR review comments | `github-mcp-server-pull_request_read` on recent PRs | **Repeated review feedback = conventions that should be in copilot-instructions.md** | +| Releases | `gh release list --limit 5 | cat` (bash) | Release cadence, versioning scheme | +| GitHub Actions workflows | `github-mcp-server-actions_list` or read `.github/workflows/` | CI/CD setup, what runs on PRs | +| Branch protection | `github-mcp-server-list_branches` | Default branch, protection rules | +| Push permissions | `gh api repos/{owner}/{repo} --jq '.permissions.push' | cat` (bash) | Whether the user can push directly or needs to fork | + +## 0c. PR review mining details + +This is the **highest-value** GitHub-native insight. Look at the 5-10 most recent merged PRs. + +*Why?*: If a maintainer leaves the same review comment on 5 different PRs, that's a convention waiting to be documented. Mining PR reviews turns reviewer fatigue into automated guidance. + +1. Use `github-mcp-server-list_pull_requests` (state: closed, sort: updated) to find recent merged PRs +2. For each, use `github-mcp-server-pull_request_read` (method: get_review_comments) to read review threads +3. Look for **repeated patterns** — the same feedback given across multiple PRs becomes a convention: + - "Please add tests for this" → add to test conventions + - "Use X pattern instead of Y" → add to coding conventions + - "Update the docs when you change this" → add to maintenance matrix + - "Don't forget to update the changelog" → add to maintenance matrix + +**If few or no review comments are found** (e.g., PRs are self-merged or auto-merged), expand the search to up to 20 merged PRs. If there are still no review patterns, note this in the findings: _"No PR review patterns found — consider adding conventions as the team grows."_ Never silently skip this section. + +These mined conventions go directly into `copilot-instructions.md` — turning repeated human review feedback into automated AI guidance. + +## 0d. Community health gap mapping + +GitHub's community health API tells you exactly what's missing. Map it to the assets this skill generates: + +| GitHub says missing | Skill generates | +|-------------------|-----------------| +| No issue templates | `.github/ISSUE_TEMPLATE/` (Step 6) | +| No pull request template | `.github/PULL_REQUEST_TEMPLATE.md` (Step 6) | +| No CONTRIBUTING guide | README Contributing section (Step 7) | +| No CODE_OF_CONDUCT | Can suggest adding one | +| No license | Flag in the report | +| No README | Flag in the report | diff --git a/.github/skills/ai-ready/references/report-template.md b/.github/skills/ai-ready/references/report-template.md new file mode 100644 index 0000000..1579990 --- /dev/null +++ b/.github/skills/ai-ready/references/report-template.md @@ -0,0 +1,191 @@ +# Report Template Reference + +Display format for the AI-Readiness Report (Step 11), HTML report, badge, and PR creation. + +## AI-Readiness Report format + +Calculate the score by counting how many assets have **Nailed It** status. Determine the maturity level from the count. Build the progress bar using 🟩 for nailed, 🟨 for could-be-better, and ⬜ for missing — always 12 squares. + +Display this report: + +``` +🎯 **AI-Readiness Report** + +Your repo is about to get a whole lot easier to contribute to — and +a whole lot faster to review. AI agents will know your conventions, +follow your patterns, and deliver PRs that are ready to merge. + +**{repo-name}** + +--- + +📊 **Your Repo Today** · {medal} **{level-name}** · {progress-bar} · {nailed} of 12 nailed +{languages} · {frameworks} · {test-runner} ({test-count}) · `{build-command}` + +🤖 **Existing AI Config (detected)** + +_Include this section only if the repo already has AI configuration (copilot-instructions.md, custom agents, custom skills). Omit it entirely if there is no pre-existing AI config._ + +| Asset | Detail | +|-------|--------| +| {asset-name} | {detail — e.g., "542 lines — components, testing, shims, docs"} | +| {.github/agents/} | {count} agents: {names} | +| {.github/skills/} | {count} skills: {names} | + +⚠️ **Instruction Consistency** + +_Show this section when consistency issues are found — skip it when everything lines up._ + +| Issue | Files | Detail | +|-------|-------|--------| +| {issue-type} | {file1} ↔ {file2} | {specific contradiction or duplication} | + +✅ **Nailed It ({count})** + +| Asset | Detail | +|-------|--------| +| {asset-name} | {one-line detail} | +| ... | ... | + +💡 **Could Be Better ({count})** + +| Asset | Suggestion | +|-------|-----------| +| {asset-name} | {suggestion} | +| ... | ... | + +_Why these matter:_ {brief explanation of why the could-be-better items are worth improving} + +⭕ **Missing ({count})** + +| Asset | Why it matters | +|-------|---------------| +| {asset-name} | {why it matters} | +| ... | ... | + +_Why these matter:_ {brief explanation of what the missing items cost the repo} + +--- + +🛠️ **What I'd Like To Do** — proposed changes to close the gaps: + +| Action | Detail | +|--------|--------| +| ➕ Create | `{filename}` — {what it will contain} | +| 🔍 Audit | `{filename}` — {what drifted and suggested fix} | +| ⏭️ Skip | `{filename}` — skipped (user requested) | +| 💬 Suggest | {suggestion} | +| ✅ Skip | {count} files already in great shape | + +_For monorepos: list each `.github/instructions/{area}.instructions.md` file created as a separate ➕ Create row._ + +--- + +🏆 **If You Accept** · {after-progress-bar} · {after-nailed} of 12 nailed → {after-medal} **{after-level}** + +🤖 AI Context {5 status indicators} +🔧 Dev Workflow {4 status indicators} +📖 Onboarding {3 status indicators} + +--- + +🚀 **What's Next?** + +👉 **Create the PR now** — just say: +\``` +create a branch and open a PR with these changes +\``` + +👉 **Tweak first** — tell me what to change: +\``` +update the AGENTS.md to include more detail about the command registration pattern +\``` + +👉 **Share the report** — want a visual version for your team? +\``` +generate an HTML report I can share +\``` + +👉 **Skip for now** — no worries, the analysis is done. Come back anytime and say `make this repo ai-ready` to pick up where you left off. +``` + +## Report template rules + +- **Nailed It** = asset exists and is well-customized to the repo +- **Could Be Better** = asset exists but has gaps or could be enhanced +- **Missing** = asset does not exist and should be created +- If a section has 0 items (e.g., nothing missing), omit that section entirely +- The tech profile table should only include rows that apply (e.g., skip "Frameworks" if none detected) +- Keep each detail to one short line — no multi-line descriptions +- The "What I Did" section should list every file that was created, suggested, or skipped +- **Show an updated progress bar** after the "What I Did" section — recount nailed assets (counting all created files as now "Nailed It"), determine the new medal, and show the category breakdown. This shows the user the improvement visually (e.g., going from 🥈 On Track · 🟩🟩🟩🟩🟩🟨⬜⬜⬜⬜⬜⬜ · 5 of 12 → 🏆 AI-Ready · 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 · 12 of 12) +- The "What To Do Next" section should include only the bullet points that are relevant — e.g., if no files were created, skip "review generated files" and instead say something like "Your repo is already AI-ready — nice work!" + +## HTML report (optional) + +*Why?*: Terminal reports are great for the developer running the skill. But when you need to share results with a manager, post to a wiki, or attach to an email — you need something visual. + +If the user asks for an HTML report (e.g., "generate a report I can share", "make an HTML report"), generate a self-contained `ai-ready-report.html` in the repo root. + +The HTML report mirrors the terminal summary — same sections, same data, same structure: + +1. **Header** — repo name, maturity level with emoji medal (🥉🥈🥇🏆), weighted score percentage, progress bar, generation date +2. **Tech profile** — languages, frameworks, test runner, build command +3. **Existing AI config** — if detected (copilot-instructions.md, custom agents/skills) +4. **Instruction consistency** — if issues found +5. **Asset status** — three groups: ✅ Nailed It, 💡 Could Be Better, ⭕ Missing — with one-line details per asset +6. **What was generated** — action table (➕ Create, 🔍 Audit, ⏭️ Skip, 💬 Suggest) +7. **Updated score** — before/after with maturity level change +8. **What to do next** — remaining recommendations + +The file must be self-contained (inline CSS, no external dependencies) and shareable — one file you can open in any browser or drop into an email. Use green/amber/gray status colors, system fonts, and a responsive layout. Keep it simple — this is a summary, not a dashboard. + +Generate the HTML report only when the user asks for it. The terminal output is always the default. + +## 11a. AI-Ready badge + +Check if the README already contains an `AI--Ready` badge. If it does not, **automatically** insert this badge at the top of the README, after any existing title or badge row — do not ask, just add it: + +```markdown +[![AI Ready](https://img.shields.io/badge/AI--Ready-yes-brightgreen?style=flat)](https://github.com/johnpapa/ai-ready) +``` + +The badge is a static Shields.io image with zero dependencies. It links back to the ai-ready repo so others can discover it. Include this in the "What I Did" section of the report as a `➕ Create` action. + +## 11b. PR creation flow + +After displaying the report and handling the badge, **ask the user** if they want to create a branch and open a PR. Do not tell them to type a command — ask them directly: + +_"Would you like me to create a branch and open a PR with these changes?"_ + +If the user agrees: + +1. **Check push permissions** from Step 0b. +2. **If the user has push access**: create a feature branch (e.g., `feat/ai-ready-config`), commit all new/modified files (including the badge), push, and open a PR targeting the **default branch** (detected in Step 0b — never assume `main`). +3. **If the user does NOT have push access**: use a fork-based flow automatically — fork the repo (`gh repo fork --clone=false`), add the fork as a remote, push the branch to the fork, then open a cross-fork PR (`gh pr create --head {user}:feat/ai-ready-config`). Handle it end-to-end — never ask the user to figure out the fork workflow. + +Include a summary of what was added and the before/after score in the PR body. If the user declines, end the session gracefully. + +**Always add a report comment to the PR.** After creating the PR, post a comment with a condensed version of the AI-Readiness Report: + +``` +## 🎯 AI-Readiness Report + +**{repo-name}** + +**Before:** {before-medal} **{before-level}** · {before-nailed} of 12 nailed +**After this PR:** {after-medal} **{after-level}** · {after-nailed} of 12 nailed + +🤖 AI Context {status indicators} +🔧 Dev Workflow {status indicators} +📖 Onboarding {status indicators} + +| Action | File | +|--------|------| +| ➕ Create | `{filename}` | +| ... | ... | + +Generated by [ai-ready](https://github.com/johnpapa/ai-ready) +``` + +*Why?*: The PR body is written once, but the report comment is what reviewers see first. A consistent, scannable summary makes it easy to understand the impact at a glance. diff --git a/.github/skills/ai-ready/references/training-repos.md b/.github/skills/ai-ready/references/training-repos.md new file mode 100644 index 0000000..728f772 --- /dev/null +++ b/.github/skills/ai-ready/references/training-repos.md @@ -0,0 +1,57 @@ +# Training Repos + +This skill's heuristics — especially course detection, notebook handling, and multi-language support — were trained and validated against these repos. Use them for regression testing when making changes to the skill. + +## Course/Tutorial repos + +- `github/copilot-cli-for-beginners` — Copilot CLI course (markdown + Python) +- `microsoft/ai-agents-for-beginners` — AI agents course (markdown + notebooks + Python/C#) +- `microsoft/generative-ai-for-beginners` — GenAI course (markdown + notebooks + Python/JS/TS) +- `microsoft/mcp-for-beginners` — MCP tutorial (markdown + TS/Python/Java/C#) +- `microsoft/langchainjs-for-beginners` — LangChain.js course (markdown + TypeScript) +- `microsoft/langchain-for-beginners` — LangChain course (markdown + Python) +- `microsoft/langchain4j-for-beginners` — LangChain4j course (markdown + Java) +- `microsoft/ML-For-Beginners` — Machine Learning course (markdown + notebooks + Python) +- `microsoft/Web-Dev-For-Beginners` — Web development course (markdown + JS/HTML/CSS) +- `microsoft/AI-For-Beginners` — AI course (markdown + notebooks + Python) +- `microsoft/Data-Science-For-Beginners` — Data science course (markdown + notebooks + Python) +- `microsoft/IoT-For-Beginners` — IoT course (markdown + hardware samples) +- `microsoft/Generative-AI-for-beginners-dotnet` — GenAI .NET course (markdown + C#) +- `microsoft/generative-ai-for-beginners-java` — GenAI Java course (markdown + Java) +- `microsoft/AZD-for-beginners` — Azure Developer CLI tutorial (markdown + CLI examples) +- `microsoft/edgeai-for-beginners` — Edge AI course (markdown + sample apps) +- `microsoft/xr-development-for-beginners` — XR/Unity course (markdown + Unity/C#) + +## Application repos + +- `johnpapa/vscode-peacock` — VS Code functional extension (TypeScript, Mocha tests) +- `johnpapa/shopathome` — Multi-framework shopping app (Angular 21, React 19, Svelte 5, Vue 3.5, Fastify 5, Azure Functions v4) +- `johnpapa/angular-styleguide` — Documentation-only style guide (markdown) +- `johnpapa/heroes-angular` — Standard Angular SPA with json-server backend, Cypress, proxy config +- `johnpapa/heroes-vue` — Vue SPA with separate API package, not a monorepo +- `johnpapa/heroes-react` — React SPA (CRA-era) with json-server, proxy, Docker, env files + +## npm packages + +- `johnpapa/lite-server` — Small CLI package (JS, Mocha/Istanbul tests, bin/ entry point) + +## Multi-app collections + +- `johnpapa/hello-worlds` — Angular/React/Svelte/Vue demos, independent apps, no workspace +- `johnpapa/http-interceptors` — Same concept in Angular + Svelte, comparison monorepo + +## VS Code extension variants + +- `johnpapa/vscode-cloak` — Functional extension (TypeScript, webpack, commands + settings) +- `johnpapa/vscode-winteriscoming` — Theme extension (JSON theme files, no runtime code) +- `johnpapa/vscode-angular-snippets` — Snippets extension (JSON snippets, language-scoped, devcontainer) + +## Large open-source library monorepos + +- `langchain-ai/langchain` — Python multi-package monorepo (`libs/*`), pyproject.toml per package, AGENTS.md + CLAUDE.md +- `langchain-ai/langchainjs` — TypeScript monorepo (pnpm + Turborepo + Changesets), workspace packages under `libs/` +- `langchain4j/langchain4j` — Java Maven aggregator with 30+ modules, JDK-conditional builds, Spotless formatting + +## Real-world field tests + +- `FritzAndFriends/BlazorWebFormsComponents` — .NET multi-target library (Blazor, C#) diff --git a/.github/skills/commit-message-storyteller/SKILL.md b/.github/skills/commit-message-storyteller/SKILL.md new file mode 100644 index 0000000..21f0dd1 --- /dev/null +++ b/.github/skills/commit-message-storyteller/SKILL.md @@ -0,0 +1,142 @@ +--- +name: commit-message-storyteller +description: 'Analyzes git diffs or staged changes and generates narrative commit messages that explain WHY a change was made, not just what changed — following Conventional Commits format. Use when asked to "write a commit message", "generate a commit", "describe my changes", "what should I commit this as", "commit this", "summarize my diff", or "help me commit". Works with git diff output, staged files, or plain descriptions of changes.' +--- + +# Commit Message Storyteller + +Transforms raw git diffs and change descriptions into clear, story-driven commit messages that follow the [Conventional Commits](https://www.conventionalcommits.org/) specification. Instead of "update file.js", you get messages that communicate intent, context, and impact. + +## When to Use This Skill + +- User says "write a commit message", "help me commit", or "generate a commit" +- User pastes a git diff or describes code changes +- User says "what should I commit this as?" or "summarize my diff" +- User wants better commit history for their team or open-source project +- User is preparing a pull request and wants meaningful commit messages + +## Prerequisites + +Have at least one of the following ready: +- Output from `git diff` or `git diff --staged` +- A description of what you changed and why +- A list of modified files + +## How It Works + +### Step 1: Gather the Change Context + +Ask the user (or infer from the diff) for: + +1. **What changed** — files, functions, logic affected +2. **Why it changed** — bug fix, new feature, refactor, performance, etc. +3. **Who/what triggered it** — issue number, user request, tech debt, etc. + +If the user provides a raw `git diff`, extract this context automatically from the diff. + +### Step 2: Identify the Commit Type + +Map the change to a Conventional Commits type using this guide: + +| Type | Use When | +|------|----------| +| `feat` | A new feature or capability is added | +| `fix` | A bug or incorrect behavior is corrected | +| `refactor` | Code restructured without changing behavior | +| `perf` | A change that improves performance | +| `docs` | Documentation only changes | +| `style` | Formatting, whitespace, missing semicolons (no logic change) | +| `test` | Adding or updating tests | +| `chore` | Build process, dependency updates, config changes | +| `ci` | CI/CD pipeline changes | +| `revert` | Reverting a previous commit | + +See `references/conventional-commits-guide.md` for detailed examples. + +### Step 3: Write the Commit Message + +Follow this structure: + +``` +(): + + + +