Skip to content

Conversation

@ibihim
Copy link

@ibihim ibihim commented Oct 30, 2025

Adds a new config plugin that provides tools to customize Claude Code:

  • /config:install-hooks - Installs session prompt capture hook for use in status line
  • /config:install-status-line - Installs enhanced status line

The session-prompt-hook captures prompts to /tmp/prompts-{session_id}.txt and the status line displays version, model, branch, output style, and the most recent prompt for improved session context awareness.

Requirements: jq

What this PR does / why we need it:

Which issue(s) this PR fixes:

Fixes

Special notes for your reviewer:

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.

@openshift-ci openshift-ci bot requested review from enxebre and stbenjam October 30, 2025 16:25
@openshift-ci
Copy link

openshift-ci bot commented Oct 30, 2025

Hi @ibihim. Thanks for your PR.

I'm waiting for a github.com member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@openshift-ci openshift-ci bot added the needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. label Oct 30, 2025
@theobarberbany
Copy link
Contributor

/ok-to-test

@openshift-ci openshift-ci bot added ok-to-test Indicates a non-member PR verified by an org member that is safe to test. and removed needs-ok-to-test Indicates a PR that requires an org member to verify it is safe to test. labels Oct 30, 2025
@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Nov 5, 2025
@openshift-merge-robot
Copy link
Contributor

PR needs rebase.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 5, 2025

Caution

Review failed

Failed to post review comments

Walkthrough

Adds three new plugins (config, olm, must-gather) with manifests, READMEs, and docs; adds many must-gather analysis scripts and extensive plugin documentation; introduces generator scripts to build PLUGINS.md and docs/data.json, a website (docs/index.html), a claudelint custom rule and config, Makefile update, and CI/workflow edits.

Changes

Cohort / File(s) Summary
Marketplace & Catalog
/.claude-plugin/marketplace.json, PLUGINS.md, docs/data.json
Registers multiple plugins (including config, olm, must-gather); updates public plugin catalog and full PLUGINS.md index; adds comprehensive plugin/command metadata in docs/data.json.
Website generator & docs tooling
scripts/generate_plugin_docs.py, scripts/build-website.py, Makefile, docs/index.html, docs/README.md
Adds scripts to generate PLUGINS.md and docs/data.json, a Makefile update target, and a static marketplace UI at docs/index.html; documents site build and usage.
Linting / CI
.claudelint-custom.py, .claudelint.yaml, .github/workflows/lint-plugins.yml
Adds a custom claudelint rule (plugins-doc-up-to-date) that runs the generator and compares outputs; registers the rule in config; removes PR path filters and a PR-comment step from lint workflow.
Config plugin
plugins/config/.claude-plugin/plugin.json, plugins/config/README.md, plugins/config/commands/*, plugins/config/scripts/*
Adds config plugin manifest, README, two command docs (install-hooks, install-status-line), and two scripts: session-prompt-hook.sh (appends prompts) and status_line.sh (builds a colorized one-line status).
OLM plugin
plugins/olm/.claude-plugin/plugin.json, plugins/olm/README.md, plugins/olm/commands/*.md
Adds olm plugin manifest, README, and multiple command docs (install, list, status, debug, catalog, approve, diagnose, uninstall, upgrade, search).
Must-gather plugin & analyzer
plugins/must-gather/.claude-plugin/plugin.json, plugins/must-gather/README.md, plugins/must-gather/commands/analyze.md, plugins/must-gather/skills/.../scripts/*.py, plugins/must-gather/skills/*/SKILL.md
Adds must-gather plugin manifest, README, analyze command doc, skill docs, and many analyzer Python scripts (clusteroperators, clusterversion, etcd, events, network, nodes, pods, pvs).
Other plugin docs & skills
plugins/git/..., plugins/jira/..., plugins/openshift/..., plugins/prow-job/..., plugins/olm/...
Adds and expands documentation across existing plugins (new commands, command docs, and many SKILL.md files for Jira, OpenShift, Prow Job, Git, etc.).
Repository metadata
OWNERS, README.md, docs/data.json
Updates owners (adds approver/reviewer), central README references PLUGINS.md and documents plugin-doc update workflow; consolidates plugin metadata in docs/data.json.

Sequence Diagram(s)

sequenceDiagram
    participant CC as Claude Code
    participant Hook as session-prompt-hook.sh
    participant FS as /tmp/claude-sessions
    participant SL as status_line.sh

    CC->>Hook: on prompt submit (JSON: session_id, prompt)
    activate Hook
    Hook->>Hook: parse JSON, normalize single-line prompt
    Hook->>FS: ensure dir, append to prompts-<SESSION_ID>.txt
    deactivate Hook

    CC->>SL: request status (JSON payload)
    activate SL
    SL->>SL: parse fields via jq (version, model, cwd, style, session_id)
    SL->>FS: read last prompt from prompts-<SESSION_ID>.txt (if present)
    SL->>SL: compute git/path context, truncate, format with colors/emojis
    SL->>CC: return single-line status string
    deactivate SL
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Areas needing extra attention:
    • .claudelint-custom.py behavior (timeout, subprocess invocation, file restoration) and its interaction with generator scripts.
    • scripts/generate_plugin_docs.py and scripts/build-website.py parsing of frontmatter and robustness against varied markdown formats.
    • Many new Python analyzer scripts under plugins/must-gather/skills/.../scripts/ (edge cases, file-glob patterns, YAML/JSON parsing and error handling).
    • Shell scripts session-prompt-hook.sh and status_line.sh (jq access patterns, null handling, directory/file permission assumptions).
    • docs/data.json and PLUGINS.md generation correctness (duplicate entries, consistency with marketplace.json).
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
plugins/config/scripts/session-prompt-hook.sh (1)

5-10: Optimize stdin parsing and add error handling for jq.

Parsing stdin twice via separate jq invocations is inefficient. Parse once and extract both fields. Additionally, add error handling—jq failures (missing jq binary, malformed JSON) should not silently fail.

Consider parsing stdin once and validating output:

-# Read JSON input from stdin
-input=$(cat)
-
-# Extract session_id and prompt
-SESSION_ID=$(echo "$input" | jq -r '.session_id // empty')
-PROMPT=$(echo "$input" | jq -r '.prompt // empty')
-
-# Exit if we couldn't extract required data
-if [ -z "$SESSION_ID" ] || [ -z "$PROMPT" ]; then
-    exit 0
-fi
+# Read JSON input from stdin once
+input=$(cat)
+
+# Extract session_id and prompt; exit gracefully on jq error
+parsed=$(echo "$input" | jq -r '.session_id, .prompt' 2>/dev/null) || exit 0
+SESSION_ID=$(echo "$parsed" | sed -n '1p')
+PROMPT=$(echo "$parsed" | sed -n '2p')
+
+# Exit if we couldn't extract required data
+if [ -z "$SESSION_ID" ] || [ -z "$PROMPT" ]; then
+    exit 0
+fi
plugins/config/commands/install-hooks.md (1)

11-13: Add language specifiers to fenced code blocks.

Markdown code blocks should specify a language for syntax highlighting. Update the blocks to use ```bash or ```shell instead of ```.

-```
+```bash
 /config:install-hooks
-```
+```

...

-```
+```bash
 /config:install-hooks
-```
+```

...

-```
+```bash
 Installed session-prompt-hook.sh to ~/.claude/
 ...
-```
+```

Also applies to: 62-73

plugins/config/scripts/status_line.sh (1)

6-11: Optimize jq invocations and add error handling.

Five separate jq calls parse the same stdin. Consolidate into a single invocation and add error handling for missing jq or malformed JSON.

-# Extract values using jq
-VERSION=$(echo "$input" | jq -r '.version')
-MODEL_DISPLAY=$(echo "$input" | jq -r '.model.display_name')
-CURRENT_DIR=$(echo "$input" | jq -r '.workspace.current_dir')
-OUTPUT_STYLE=$(echo "$input" | jq -r '.output_style.name')
-SESSION_ID=$(echo "$input" | jq -r '.session_id')
+# Extract all values in one jq call; exit gracefully on error
+parsed=$(echo "$input" | jq -r '.version, .model.display_name, .workspace.current_dir, .output_style.name, .session_id' 2>/dev/null) || exit 1
+VERSION=$(echo "$parsed" | sed -n '1p')
+MODEL_DISPLAY=$(echo "$parsed" | sed -n '2p')
+CURRENT_DIR=$(echo "$parsed" | sed -n '3p')
+OUTPUT_STYLE=$(echo "$parsed" | sed -n '4p')
+SESSION_ID=$(echo "$parsed" | sed -n '5p')
plugins/config/commands/install-status-line.md (1)

11-13: Add language identifiers to fenced code blocks.

Five code blocks lack language specifiers, which violates markdown linting rules (MD040). Specify appropriate languages for each block to improve readability and enable syntax highlighting:

  • Line 11-13 (synopsis): Use bash for the command syntax
  • Lines 76-90 (basic installation output): Use text or output for expected output
  • Lines 93-97 (full setup example): Use bash for the command sequence
  • Lines 110-112 (example output): Use text or output for the status line example

Apply this diff to add language specifiers:

 ## Synopsis
 
-\```
+\```bash
 /config:install-status-line
-\```
+\```
 
 ...
 
 1. **Basic installation**:
-   \```
+   \```bash
    /config:install-status-line
-   \```
+   \```
    Expected output:
-   \```
+   \```text
    Installed status_line.sh to ~/.claude/
 
    To enable the status line, run:
@@ -90,7 +90,7 @@ Expected output:
    Or manually edit your Claude Code settings.
 
    Status line format:
-   \```
+   \```bash
    /config:install-hooks
    /config:install-status-line
-   \```
+   \```
    Complete installation of both components for full functionality.
 
@@ -108,7 +108,7 @@ The status line displays information with color-coded sections:
 - **Grey**: Last user prompt (truncated at 50 chars)
 
 Example output:
-\```
+\```text
 v1.2.3 | Sonnet 4.5 | main | default | I would like to contribute ~/.clau...
-\```
+\```

Also applies to: 76-90, 93-97, 110-112

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between abd54a3 and d3e645d.

📒 Files selected for processing (9)
  • .claude-plugin/marketplace.json (1 hunks)
  • PLUGINS.md (2 hunks)
  • docs/data.json (1 hunks)
  • plugins/config/.claude-plugin/plugin.json (1 hunks)
  • plugins/config/README.md (1 hunks)
  • plugins/config/commands/install-hooks.md (1 hunks)
  • plugins/config/commands/install-status-line.md (1 hunks)
  • plugins/config/scripts/session-prompt-hook.sh (1 hunks)
  • plugins/config/scripts/status_line.sh (1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
plugins/config/commands/install-hooks.md

11-11: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


62-62: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


66-66: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/config/commands/install-status-line.md

11-11: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


76-76: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


80-80: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


93-93: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


110-110: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (8)
plugins/config/.claude-plugin/plugin.json (1)

1-8: LGTM!

Plugin manifest is well-structured and consistent with other plugins in the repository.

PLUGINS.md (1)

7-7: LGTM!

Config Plugin is properly integrated into the PLUGINS catalog. TOC entry is alphabetically ordered, and the section follows established formatting conventions.

Also applies to: 42-50

.claude-plugin/marketplace.json (1)

32-36: LGTM!

Marketplace entry is properly structured with correct source path and description matching documentation.

plugins/config/scripts/status_line.sh (1)

23-32: Verify git command behavior outside repositories.

Lines 23–32 attempt to detect the current git branch. If git rev-parse --git-dir or git branch fail (e.g., outside a repo or with permission issues), the script still executes but GIT_INFO remains empty, and the final status line shows an empty segment.

Confirm that this graceful degradation is acceptable, or consider adding logging to surface git errors. Also note: git commands assume the current working directory is relevant; they may behave unexpectedly if run outside the intended context.

docs/data.json (2)

199-219: Config plugin entry is well-structured.

The config plugin entry follows the established pattern, with both commands (install-hooks, install-status-line) properly documented with descriptions, synopsis, and argument hints.


199-219: Only one config plugin entry exists in docs/data.json (line 200). No duplicates found.

plugins/config/README.md (1)

1-103: LGTM!

Comprehensive and well-structured plugin documentation. Installation steps are clear, prerequisites are well-documented with platform-specific commands, and the explanation of optional vs. required features is helpful.

plugins/config/commands/install-status-line.md (1)

1-125: Documentation is clear and well-structured.

The documentation effectively explains the command's purpose, prerequisites, usage, and examples. Prerequisites section is particularly comprehensive with platform-specific installation instructions for dependencies. Cross-references to /config:install-hooks and the status line script are consistent and helpful for users.

PROMPT_SINGLE_LINE=$(echo "$PROMPT" | tr '\n' ' ' | sed 's/ */ /g')

# Append to session-specific file in /tmp
echo "$PROMPT_SINGLE_LINE" >> "/tmp/prompts-${SESSION_ID}.txt"
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 5, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Clarify intent for /tmp storage and consider ACL implications.

Writing prompts to /tmp/prompts-${SESSION_ID}.txt creates world-readable files. If prompts contain sensitive data (API keys, internal details, etc.), consider:

  1. Using a restricted directory (e.g., ~/.claude/prompts/ with 0700 permissions)
  2. Documenting the security model and potential data exposure
  3. Adding a cleanup mechanism (e.g., on session end)

Confirm whether storing user prompts in world-readable /tmp aligns with the security/privacy model of Claude Code.


🏁 Script executed:

#!/bin/bash
# Examine the session-prompt-hook.sh file to understand full context
cat plugins/config/scripts/session-prompt-hook.sh

Length of output: 612


🏁 Script executed:

#!/bin/bash
# Search for other /tmp references related to prompts in the codebase
rg -n "tmp.*prompt|prompt.*tmp" --type sh --type js --type py -i

Length of output: 197


🏁 Script executed:

#!/bin/bash
# Search for cleanup mechanisms or session cleanup patterns
rg -n "cleanup|rm.*tmp|unlink|remove.*session" --type sh --type js --type py -C 2

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for security, privacy, or data storage documentation
fd -e md -e txt -e rst | xargs grep -l -i "security\|privacy\|data.*storage\|sensitive" 2>/dev/null | head -20

Length of output: 705


🏁 Script executed:

#!/bin/bash
# Check for alternative secure storage mechanisms in the codebase
rg -n "\.claude|config.*dir|secure.*storage|encrypted" --type sh --type js --type py -i

Length of output: 307


🏁 Script executed:

#!/bin/bash
# Examine status_line.sh to understand how prompts are being used
cat plugins/config/scripts/status_line.sh

Length of output: 1534


🏁 Script executed:

#!/bin/bash
# Search for documentation in the config/scripts directory
find plugins/config/scripts -type f \( -name "*.md" -o -name "README*" -o -name "*.txt" \) 

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for any setup or initialization that may configure /tmp permissions
rg -n "chmod|umask|tmp.*permission|secure.*tmp" --type sh -i

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for any session management or cleanup on exit
rg -n "EXIT|SIGTERM|trap|on.*exit|atexit" --type sh -A 3 -B 1

Length of output: 0


Address world-readable /tmp storage for user prompts and add session cleanup.

The concerns are verified: prompts are written to /tmp/prompts-${SESSION_ID}.txt with default world-readable permissions, persisted indefinitely with no cleanup mechanism. Implement at minimum:

  1. Store prompts in ~/.claude/prompts/ (or equivalent user-specific directory) with 0700 permissions instead of /tmp
  2. Add cleanup logic to remove session prompt files on session end (trap handler or explicit cleanup function)
  3. Document this design decision and any data retention/privacy implications

The feature reads prompts for display in status_line.sh, but the security model should not trade user data visibility for convenience.

Copy link
Author

Choose a reason for hiding this comment

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

I personally used https://github.com/charmbracelet/skate for this, but I didn't want to push any dependencies and went for /tmp.

Copy link
Contributor

Choose a reason for hiding this comment

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

@ibihim I appreciate the dependency concern—keeping the plugin lightweight is a valid goal. However, you can achieve better security without adding external dependencies by using a user-specific directory like ~/.claude/prompts/:

# Create directory with restrictive permissions (no external deps needed)
PROMPT_DIR="$HOME/.claude/prompts"
mkdir -p "$PROMPT_DIR"
chmod 700 "$PROMPT_DIR"

# Write to the protected directory
echo "$PROMPT_SINGLE_LINE" >> "$PROMPT_DIR/prompts-${SESSION_ID}.txt"

This approach:

  • Uses only standard shell utilities (mkdir, chmod)—no external dependencies
  • Prevents other users from reading prompts that might contain sensitive data
  • Keeps prompts organized in the same .claude directory as other config

If you prefer to keep /tmp for simplicity, I'd suggest at least:

  1. Documenting in the README that prompts are stored world-readable in /tmp
  2. Warning users not to include sensitive information in prompts if multi-user systems are a concern
  3. Considering a cleanup mechanism (even a simple note about manually removing /tmp/prompts-* files)

What are your thoughts on using ~/.claude/prompts/ as a middle ground?

@openshift-ci
Copy link

openshift-ci bot commented Nov 14, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: ibihim
Once this PR has been reviewed and has the lgtm label, please assign mrunalp for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
plugins/config/commands/install-hooks.md (1)

11-13: Add language specifiers to fenced code blocks.

The markdown linter flagged code blocks without language specifiers. While technically valid, specifying a language improves readability and enables syntax highlighting.

Apply this diff to add language specifiers:

 ## Synopsis
 
-```
+```bash
 /config:install-hooks

```diff
 1. **Basic installation**:
-   ```
+   ```bash
    /config:install-hooks
    ```
    Expected output:
-   ```
+   ```json
    Installed session-prompt-hook.sh to ~/.claude/

Also applies to: 79-82, 83-104

plugins/config/commands/install-status-line.md (1)

86-106: Add language specifiers to fenced code blocks.

The markdown linter flagged code blocks without language specifiers. Improve readability and enable syntax highlighting.

Apply this diff:

 1. **Basic installation**:
-   ```
+   ```bash
    /config:install-status-line
    ```
    Expected output:
-   ```
+   ```
    Installed status_line.sh to ~/.claude/
    
    To enable the status line, add to ~/.claude/settings.json:
    
    {
      "statusLine": {
        "type": "command",
        "command": "/home/YOUR_USERNAME/.claude/status_line.sh"
      }
    }
    
    Then restart Claude Code or start a new session.
    
    Status line format:
    [version] | [model] | [branch/dir] | [style] | [last prompt...]
-   ```
+   ```
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between d3e645d and 42d3830.

📒 Files selected for processing (3)
  • plugins/config/README.md (1 hunks)
  • plugins/config/commands/install-hooks.md (1 hunks)
  • plugins/config/commands/install-status-line.md (1 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
plugins/config/commands/install-hooks.md

11-11: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


79-79: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


83-83: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/config/commands/install-status-line.md

114-114: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (4)
plugins/config/commands/install-status-line.md (1)

67-82: Clear and helpful prerequisite documentation.

The prerequisites section clearly distinguishes between required (jq) and optional dependencies (git, session-prompt-hook). This is good UX—it helps users understand what's essential vs. nice-to-have.

plugins/config/README.md (2)

1-123: Well-structured and user-friendly README.

The README provides clear, layered information: overview, minimal setup path, optional enhancements, and requirements. The distinction between required and optional components (jq vs. git, and prompt hook as optional enhancement) helps users make informed decisions. JSON examples are clear and highlight the USERNAME replacement requirement.


36-40: Plugin installation command is correct.

The format /plugin install config@ai-helpers follows the documented Claude Code syntax of /plugin install <plugin-name>@<marketplace-name>. The script output confirms the plugin is properly registered in the "ai-helpers" marketplace with valid metadata.

plugins/config/commands/install-hooks.md (1)

34-48: Clarify that the documentation files shown are actually consistent, and the comparison to install-status-line.md is not valid.

The review comment contains an error. Both install-hooks.md and README.md show the same nested hook structure (consistent with each other). Additionally, the comparison to install-status-line.md is invalid—the files contain configurations for different features:

  • hooks configuration: Uses a nested structure {"hooks": {"UserPromptSubmit": [{"hooks": [...]}]}} to support multiple hooks per event
  • statusLine configuration: Uses a flat structure {"statusLine": {"type": "...", "command": "..."}} since it's a single feature

These are different configuration keys with no requirement to share the same structure. The nested hooks structure appears intentional and is consistently documented across both files.

Likely an incorrect or invalid review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 42d3830 and 45f0244.

📒 Files selected for processing (4)
  • plugins/config/commands/install-hooks.md (1 hunks)
  • plugins/config/commands/install-status-line.md (1 hunks)
  • plugins/config/scripts/session-prompt-hook.sh (1 hunks)
  • plugins/config/scripts/status_line.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • plugins/config/scripts/status_line.sh
  • plugins/config/scripts/session-prompt-hook.sh
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
plugins/config/commands/install-status-line.md

11-11: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


86-86: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


90-90: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


109-109: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


128-128: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

plugins/config/commands/install-hooks.md

11-11: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


86-86: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


90-90: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


109-109: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

Comment on lines +11 to +49
```
/config:install-hooks
```

## Description

The `config:install-hooks` command installs the session prompt capture hook script to `~/.claude/hooks/session-prompt-hook.sh`.
This hook captures user prompts during a Claude Code session and saves them to `/tmp/claude-sessions/prompts-{session_id}.txt`.

**Purpose**: This hook exists solely to provide the status line with your last prompt for display.
It has no other functionality and provides no value on its own.
The status line works fine without it.

## Implementation

1. **Copy hook script to Claude Code config directory**
- Source: `plugins/config/scripts/session-prompt-hook.sh`
- Destination: `~/.claude/hooks/session-prompt-hook.sh`
- Ensure the script is executable

2. **Configure Claude Code to use the hook**
- Edit `~/.claude/settings.json` and add:

```json
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "$HOME/.claude/hooks/session-prompt-hook.sh"
}
]
}
]
}
}
```
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add language specifiers to fenced code blocks.

Fenced code blocks should specify their language for proper syntax highlighting in rendered documentation. The JSON configuration block at lines 34–49 is missing the language specifier.

Apply this diff to add the language specifier:

-   ```
+   ```json
     {
       "hooks": {
         "UserPromptSubmit": [
           {
             "hooks": [
               {
                 "type": "command",
                 "command": "$HOME/.claude/hooks/session-prompt-hook.sh"
               }
             ]
           }
         ]
       }
     }
-   ```
+   ```json
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

11-11: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
plugins/config/commands/install-hooks.md around lines 11 to 49: the fenced code
block containing the JSON configuration is missing a language specifier; update
the closing and opening fence lines so the JSON block is fenced with ```json
(both start and end) — i.e., change the opening ``` before the JSON to ```json
and the trailing ``` after the JSON to ```json (ensuring only the opening fence
needs the language tag) so the block renders with JSON syntax highlighting.

}
```

- Replace `$HOME` with the actual `$HOME` environment variable
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify the $HOME replacement instruction.

Line 51 states "Replace $HOME with the actual $HOME environment variable," which is contradictory. Clarify whether users should keep $HOME as a literal string (for shell expansion) or replace it with an explicit home directory path (e.g., /home/username).

Suggested revision:

-   - Replace `$HOME` with the actual `$HOME` environment variable
+   - Keep `$HOME` as-is; the shell will expand it to your home directory when the hook runs
📝 Committable suggestion

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

Suggested change
- Replace `$HOME` with the actual `$HOME` environment variable
- Keep `$HOME` as-is; the shell will expand it to your home directory when the hook runs
🤖 Prompt for AI Agents
In plugins/config/commands/install-hooks.md around line 51, the instruction
"Replace `$HOME` with the actual `$HOME` environment variable" is ambiguous;
change it to a single clear sentence that tells users when to keep the literal
`$HOME` (for shells that will expand it) and when to use an absolute path. For
example, replace the line with: "Use the literal `$HOME` when entering commands
in a shell so it will be expanded, or if placing the path into a file that will
not perform shell expansion, replace `$HOME` with your absolute home directory
(e.g., `/home/username`)."

}
}
```
- Replace `$HOME` with the actual `$HOME` environment variable
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify the $HOME replacement instruction.

Line 46 contains the same confusing instruction as found in install-hooks.md. Clarify whether $HOME should remain as a literal string or be replaced with an explicit path.

Suggested revision:

-   - Replace `$HOME` with the actual `$HOME` environment variable
+   - Keep `$HOME` as-is; the shell will expand it to your home directory when the status line runs
📝 Committable suggestion

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

Suggested change
- Replace `$HOME` with the actual `$HOME` environment variable
- Keep `$HOME` as-is; the shell will expand it to your home directory when the status line runs
🤖 Prompt for AI Agents
In plugins/config/commands/install-status-line.md around line 46, the
instruction "Replace `$HOME` with the actual `$HOME` environment variable" is
ambiguous; change it to a clear directive that the user should substitute the
placeholder with their home directory path (not leave the literal string).
Update the line to read something like: "Replace $HOME with the absolute path to
your home directory (for example /home/yourname or C:\Users\YourName); if you
are running in a shell you may alternatively use the $HOME variable so the path
resolves at runtime."

Comment on lines +85 to +112
1. **Basic installation**:
```
/config:install-status-line
```
Expected output:
```
Installed status_line.sh to ~/.claude/

To enable the status line, add to ~/.claude/settings.json:

{
"statusLine": {
"type": "command",
"command": "$HOME/.claude/status_line.sh"
}
}

Then restart Claude Code or start a new session.

Status line format:
📦 [version] | 🧬 [model] | 🗂️ [parent/current:branch] | 🎨 [style] | 💬 [last prompt...]
```

2. **Full setup with prompt hook**:
```
/config:install-hooks
/config:install-status-line
```
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add language specifiers to example code blocks.

Code blocks in the Examples section lack language specifiers. Lines 86 (command), 90 (output), 109 (commands), and the implied block at 128 (format example) should all specify their language or format.

Apply this diff to add language specifiers:

   1. **Basic installation**:
-    ```
+    ```bash
      /config:install-status-line
-    ```
+    ```
      Expected output:
-    ```
+    ```text
      Installed status_line.sh to ~/.claude/
      
      To enable the status line, add to ~/.claude/settings.json:
      
      {
        "statusLine": {
          "type": "command",
          "command": "$HOME/.claude/status_line.sh"
        }
      }
      
      Then restart Claude Code or start a new session.
      
      Status line format:
      📦 [version] | 🧬 [model] | 🗂️ [parent/current:branch] | 🎨 [style] | 💬 [last prompt...]
-    ```
+    ```

   2. **Full setup with prompt hook**:
-    ```
+    ```bash
      /config:install-hooks
      /config:install-status-line
-    ```
+    ```
      Complete installation of both components for full functionality.
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

86-86: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


90-90: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


109-109: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In plugins/config/commands/install-status-line.md around lines 85 to 112, the
example code fences are missing language specifiers; update the first command
fence (line ~86) to use ```bash, change the expected output fence (line ~90) to
```text (so the JSON and status-line example render as plain text), change the
second command block (line ~109) to ```bash, and ensure the status-line
format/example block (around line ~128) uses ```text; keep the fence boundaries
as-is and only add the language tags.

Comment on lines +127 to +130
Example output:
```
📦 v1.2.3 | 🧬 Sonnet 4.5 | 🗂️ openshift/ai-helpers:config-plugin | 🎨 default | 💬 I would like to contribute ~/.clau...
```
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add language specifier to example output block.

The example status line output at lines 128–130 should specify a language or format specifier.

Apply this diff to add the language specifier:

   Example output:
-  ```
+  ```text
   📦 v1.2.3 | 🧬 Sonnet 4.5 | 🗂️ openshift/ai-helpers:config-plugin | 🎨 default | 💬 I would like to contribute ~/.clau...
-  ```
+  ```
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

128-128: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In plugins/config/commands/install-status-line.md around lines 127 to 130, the
example output code block lacks a language/format specifier; update the opening
triple-backtick to include a specifier (e.g., ```text) so the block becomes
```text followed by the example line and closing ``` to ensure consistent
rendering.

stbenjam and others added 16 commits November 14, 2025 18:39
It doesn't work, and folks are used to just looking at required statuses
on their PR's anyway.
Add comprehensive skills for creating different Jira issue types with templates, best practices, and interactive workflows.

Type-Specific Skills:
- create-story: User story format, acceptance criteria, 3 Cs framework
- create-epic: Epic structure, scope guidelines, parent linking
- create-feature: Market problem framework, success criteria, strategic planning
- create-task: Technical task structure, task vs story differentiation
- create-bug: Bug report template, reproduction steps, severity handling

Project-Specific Skills:
- cntrlplane: CNTRLPLANE project conventions (stories, epics, features, tasks)
- ocpbugs: OCPBUGS project conventions (bugs only)

Team-Specific Skills:
- hypershift: HyperShift team component selection (ARO/ROSA/HyperShift)

Architecture:
- No duplication across project/team skills (~1% structural duplication in type skills)
- Each skill is self-contained and independently readable
- Skills provide implementation guidance for Claude when executing /jira:create command

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Add /jira:create command that provides a single interface for creating all Jira issue types (stories, epics, features, tasks, bugs) with intelligent defaults and interactive guidance.

Command Features:
- Single unified command: /jira:create <type> [project] <summary> [options]
- Hybrid workflow: required arguments + optional flags + interactive prompts
- Universal requirements automatically applied (Security: Red Hat Employee, Labels: ai-generated-jira)
- Security validation: scans for credentials and secrets before submission
- Modular skill invocation: automatically loads type, project, and team skills

Supported Issue Types:
- story: User stories with acceptance criteria
- epic: Epics with parent feature linking
- feature: Strategic features with market problem analysis
- task: Technical tasks and operational work
- bug: Bug reports with structured templates

Usage Examples:
- /jira:create story CNTRLPLANE "Add user dashboard"
- /jira:create epic CNTRLPLANE "Mobile redesign" --parent FEATURE-100
- /jira:create bug "Login button doesn't work"
- /jira:create feature CNTRLPLANE "Advanced search"

Documentation follows man-page format with comprehensive sections for implementation, error handling, examples, and best practices.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
This will give indicators of unusual things going on in the cluster at
the time an e2e test failed, and provides helpful context when debugging
some failures.
This is a first pass idea of some skills for analyzing and extracting
basic data (from yamls, no logs yet) from Openshift must-gathers
Update the spec file save location from contrib/ to .work/jira/solve/
for better organization of JIRA solve specification documents.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Add new slash command that generates Conventional Commits format messages
with two operational modes:
- Mode 1: Analyze staged changes and suggest 3 commit messages
- Mode 2: Analyze N commits for rewriting or squashing

Includes comprehensive documentation with usage examples and type reference.
Add Git plugin section to README with command descriptions.
stbenjam and others added 13 commits November 14, 2025 18:39
Add /git:branch-cleanup command to clean up old and merged branches
with support for dry-run, merged-only, and remote deletion modes.
Includes safety checks to prevent deletion of protected branches.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Adds a comprehensive marketplace website to showcase all plugins, commands,
and skills in the ai-helpers repository:

- Interactive plugin browser with search functionality
- Linkable install instructions and plugin details
- Copy-to-clipboard install commands for each plugin
- Responsive design with dark theme
- Auto-generated from plugin metadata via `make update`
- Updated linter to verify docs/data.json stays in sync

The website is served from docs/ for GitHub Pages deployment.

Co-Authored-By: Claude <[email protected]>
Adds a new config plugin that provides tools to customize Claude Code:

- /config:install-hooks - Installs session prompt capture hook
- /config:install-status-line - Installs enhanced status line

The session-prompt-hook captures prompts to /tmp/prompts-{session_id}.txt
and the status line displays version, model, branch, output style, and the
most recent prompt for improved session context awareness.

Requirements: jq (Fedora, Arch Linux, macOS supported)
- Fix hook installation path to ~/.claude/hooks/session-prompt-hook.sh
- Add blank lines for better markdown formatting
- Improve indentation in prerequisites section
- Add spacing in examples section for better readability
- Use ${TMPDIR:-/tmp}/claude-sessions for portable temp directory
- Create claude-sessions directory if it doesn't exist
- Store prompts in organized subdirectory instead of root /tmp
- Add parent/current directory display with intelligent truncation
- Implement dual-tone green color scheme (dark/light)
- Add emoji indicators for visual scanning (📦 🧬 🗂️ 🎨 💬)
- Display path context alongside branch: "parent/current:branch"
- Use ${TMPDIR:-/tmp}/claude-sessions for prompt file location
- Truncate parent dir to 10 chars, current folder to 20 chars

Status line format:
📦 version | 🧬 model | 🗂️ parent/current:branch | 🎨 style | 💬 prompt
- Replace hardcoded /home/USERNAME paths with $HOME variable
- Update all references to /tmp/claude-sessions/ storage location
- Document new status line features: emojis, path context, truncation
- Update example outputs to reflect new format with emojis
- Fix hook installation path references to ~/.claude/hooks/
- Improve settings.json examples with $HOME variable
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 24

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugins/prow-job/skills/prow-job-analyze-test-failure/SKILL.md (1)

41-57: Fix inconsistent working-directory paths (*-test-failure vs *-resource)

The doc mixes two different base paths:

  • Step 2 and the final summary use .work/prow-job-analyze-test-failure/{build_id}/...
  • Step 4.2 and the “Store artifacts/logs” bullets reference .work/prow-job-analyze-resource/{build_id}/...

Given that this skill is prow-job-analyze-test-failure and Step 4.1 downloads build-log.txt into the *-test-failure directory, reading from and writing to *-resource instead is confusing and likely wrong.

Suggest standardizing on a single base directory for this skill, for example:

-   - Read `.work/prow-job-analyze-resource/{build_id}/logs/build-log.txt`
+   - Read `.work/prow-job-analyze-test-failure/{build_id}/logs/build-log.txt`
@@
-   - Store artifacts from Prow CI job (json/yaml files) related to the failure under `.work/prow-job-analyze-resource/{build_id}/tmp`
-   - Store logs under `.work/prow-job-analyze-resource/{build_id}/logs/`
+   - Store artifacts from Prow CI job (json/yaml files) related to the failure under `.work/prow-job-analyze-test-failure/{build_id}/tmp`
+   - Store logs under `.work/prow-job-analyze-test-failure/{build_id}/logs/`

If sharing the *-resource workspace is intentional, it’d be good to call that out explicitly and adjust the earlier download paths accordingly so the story is consistent end-to-end.

Also applies to: 75-86, 87-110, 110-116, 121-135

♻️ Duplicate comments (8)
plugins/config/commands/install-hooks.md (4)

11-11: Add language specifier to synopsis code block.

The synopsis code block should specify bash for proper syntax highlighting.

Apply this diff:

 ## Synopsis
 
-```
+```bash
 /config:install-hooks

---

`34-49`: **Add language specifier to JSON configuration block.**

The JSON configuration example needs a language specifier for proper rendering.



Apply this diff:

```diff
    - Edit `~/.claude/settings.json` and add:
 
-     ```
+     ```json
      {
        "hooks": {

82-109: Add language specifiers to example code blocks.

The example command and output blocks need language specifiers.

Apply this diff:

 1. **Basic installation**:
 
-   ```
+   ```bash
    /config:install-hooks
    ```
 
    Expected output:
 
-   ```
+   ```text
    Installed session-prompt-hook.sh to ~/.claude/hooks/

51-51: Clarify $HOME usage instruction.

The instruction "Replace $HOME with the actual $HOME environment variable" is contradictory.

Suggest this revision:

-   - Replace `$HOME` with the actual `$HOME` environment variable
+   - Keep `$HOME` as-is; the shell will expand it at runtime
plugins/config/commands/install-status-line.md (4)

11-11: Add language specifier to synopsis code block.

The synopsis should specify bash for proper syntax highlighting.

Apply this diff:

 ## Synopsis
 
-```
+```bash
 /config:install-status-line

---

`38-44`: **Add language specifier to JSON configuration block.**

The JSON example needs a language specifier.



Apply this diff:

```diff
    - Edit `~/.claude/settings.json` and add:
-     ```json
+     ```json
      {
        "statusLine": {

86-106: Add language specifiers to example blocks.

Examples need language specifiers for proper rendering.

Apply this diff:

 1. **Basic installation**:
-   ```
+   ```bash
    /config:install-status-line
    ```
    Expected output:
-   ```
+   ```text
    Installed status_line.sh to ~/.claude/

46-46: Clarify $HOME usage instruction.

The instruction is contradictory as noted in past reviews.

Suggest this revision:

-   - Replace `$HOME` with the actual `$HOME` environment variable
+   - Keep `$HOME` as-is; the shell will expand it at runtime
🧹 Nitpick comments (37)
plugins/git/README.md (1)

11-13: Consider hyphenating compound modifier.

The documentation clearly describes the command's purpose. For stylistic consistency, "Conventional Commits-style" should be hyphenated when used as a compound modifier.

Apply this diff:

-Generate Conventional Commits style commit messages for staged changes or recent commits.
+Generate Conventional Commits-style commit messages for staged changes or recent commits.
plugins/olm/commands/uninstall.md (2)

10-12: Consider adding language identifiers to fenced code blocks.

The documentation is comprehensive and well-structured. However, several fenced code blocks lack language identifiers, which can impact syntax highlighting and readability in various markdown renderers. While this doesn't affect functionality, it improves the user experience.

For example, the Synopsis block (lines 10-12) could be:

 ## Synopsis
-```
+```bash
 /olm:uninstall <operator-name> [namespace] [--remove-crds] [--remove-namespace]

Similar improvements can be made to other code blocks throughout the document where CLI commands, warnings, or output examples are shown. Consider adding appropriate identifiers like `bash` for shell commands, `yaml` for configuration examples, or `text` for plain output displays.


Also applies to: 71-81, 113-119, 131-142, 152-157, 180-187, 199-219, 240-257, 259-267, 283-302

---

`148-148`: **Consider wrapping bare URLs in angle brackets.**

Lines 148 and 377 contain bare URLs that could benefit from markdown link formatting or angle brackets for better rendering across different markdown processors.



```diff
-Reference: https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html/operators/administrator-tasks#olm-reinstalling-operators-after-failed-uninstallation_olm-troubleshooting-operator-issues
+Reference: <https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html/operators/administrator-tasks#olm-reinstalling-operators-after-failed-uninstallation_olm-troubleshooting-operator-issues>
-See: https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html/operators/administrator-tasks#olm-reinstalling-operators-after-failed-uninstallation_olm-troubleshooting-operator-issues
+See: <https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html/operators/administrator-tasks#olm-reinstalling-operators-after-failed-uninstallation_olm-troubleshooting-operator-issues>

Also applies to: 377-377

plugins/olm/commands/install.md (2)

10-12: Consider adding language identifiers to fenced code blocks.

The documentation provides excellent coverage of the installation workflow. Adding language identifiers to key code blocks would improve syntax highlighting and readability.

For example:

 ## Synopsis
-```
+```bash
 /olm:install <operator-name> [namespace] [channel] [source] [--approval=Automatic|Manual]

Consider applying similar improvements to informational messages and CLI command examples throughout the document.


Also applies to: 113-119, 131-140, 180-222

---

`243-243`: **Consider wrapping bare URL in angle brackets.**

For better markdown rendering consistency, wrap the bare URL in angle brackets.



```diff
-Reference: https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html/operators/administrator-tasks#olm-approving-operator-upgrades_olm-updating-operators
+Reference: <https://docs.redhat.com/en/documentation/openshift_container_platform/4.20/html/operators/administrator-tasks#olm-approving-operator-upgrades_olm-updating-operators>
plugins/olm/commands/debug.md (1)

10-12: Consider adding language identifiers to fenced code blocks.

The debug command documentation is comprehensive and well-structured. Adding language identifiers would enhance readability.

 ## Synopsis
-```
+```bash
 /olm:debug <issue-description> <must-gather-path> [olm-version]

Apply similar improvements to example command blocks throughout the document.


Also applies to: 186-198

</blockquote></details>
<details>
<summary>plugins/olm/commands/search.md (1)</summary><blockquote>

`10-12`: **Consider adding language identifiers to fenced code blocks.**

The search command documentation provides excellent detail about operator discovery and filtering. Adding language identifiers to fenced code blocks would improve syntax highlighting.



```diff
 ## Synopsis
-```
+```bash
 /olm:search [query] [--catalog <catalog-name>]

For the formatted output examples (lines 84-106, 109-127), consider using `text` as the language identifier for better rendering of the ASCII art borders and structured output displays.


Also applies to: 84-106, 131-133, 138-145, 169-200

</blockquote></details>
<details>
<summary>plugins/openshift/commands/create-cluster.md (1)</summary><blockquote>

`226-226`: **Use proper markdown heading syntax instead of emphasis for section headers.**

Lines 226 and 263 use bold text (`**text**`) to mark subsection headers. These should use markdown heading syntax (###) for proper document structure:

```diff
-**IMPORTANT**: Do NOT run the installer interactively. Instead, collect all required information from the user and generate the install-config.yaml programmatically.
+### Important Note
+Do NOT run the installer interactively. Instead, collect all required information from the user and generate the install-config.yaml programmatically.

-**Step 5.1: Collect Information**
+### Step 5.1: Collect Information

This improves document structure for TOC generation and accessibility.

Also applies to: 263-263

plugins/must-gather/skills/must-gather-analyzer/scripts/analyze_events.py (2)

20-31: Narrow overly broad except Exception blocks in parser and age helper

Both parse_events_file (Line 20–31) and calculate_age (Line 53–54) catch a bare Exception, which trips BLE001 and makes unexpected errors harder to spot.

Given these are CLI helpers, you can still be robust while narrowing to expected failures:

 def parse_events_file(file_path: Path) -> List[Dict[str, Any]]:
@@
-    try:
+    try:
         with open(file_path, 'r') as f:
             docs = yaml.safe_load_all(f)
@@
-    except Exception as e:
+    except (OSError, yaml.YAMLError) as e:
         print(f"Warning: Failed to parse {file_path}: {e}", file=sys.stderr)
@@
 def calculate_age(timestamp_str: str) -> str:
@@
-    except Exception:
+    except (ValueError, TypeError):
         return ""

This keeps the “best effort” behavior while avoiding swallowing unrelated exceptions.

Also applies to: 53-54


2-5: Align docstring with behavior and consider avoiding the ℹ️ glyph

  • The top-level docstring says “Shows warning and error events…” but by default you display all event types, only optionally filtered via --type. Either:

    • update the docstring to something like “Shows events (e.g., Warning/Normal) sorted by last occurrence”, or
    • default-filter to warnings and document --type Normal for changing it.
  • Ruff flags the ℹ️ character (Line 167) as ambiguous. If you want to keep linters quiet and avoid font issues, you could switch to plain text:

-    if normal > 0:
-        print(f"  ℹ️  {normal} Normal events")
+    if normal > 0:
+        print(f"  Info: {normal} Normal events")

Both are minor polish items but will make the tool’s behavior and output clearer.

Also applies to: 158-167

plugins/must-gather/skills/must-gather-analyzer/scripts/analyze_etcd.py (1)

16-21: Remove or use the unused endpoint_health data and tidy constant f-strings

  • parse_etcd_info populates etcd_data['endpoint_health'] from endpoint_health.json (Lines 56–62), but endpoint_health is never read later (only member_health, member_list, and endpoint_status are used). This is dead data and can be simplified:
-        'member_health': [],
-        'member_list': [],
-        'endpoint_health': [],
-        'endpoint_status': []
+        'member_health': [],
+        'member_list': [],
+        'endpoint_status': []
@@
-    # Parse endpoint health
-    endpoint_health_file = etcd_info_dir / "endpoint_health.json"
-    if endpoint_health_file.exists():
-        try:
-            with open(endpoint_health_file, 'r') as f:
-                data = json.load(f)
-                etcd_data['endpoint_health'] = data if isinstance(data, list) else [data]
-        except Exception as e:
-            print(f"Warning: Failed to parse endpoint_health.json: {e}", file=sys.stderr)
+    # (Optional) parse extra endpoint health details here if you need them later
  • Minor style: several print calls are constant f-strings (e.g., Lines 147, 153, 155). They can be plain strings to satisfy F541:
-    print(f"ETCD CLUSTER SUMMARY")
+    print("ETCD CLUSTER SUMMARY")

Not critical, but it simplifies the code and quiets Ruff.

Also applies to: 55-62, 171-185

plugins/must-gather/skills/must-gather-analyzer/scripts/analyze_pvs.py (2)

128-143: Add support for aggregated persistentvolumes.yaml to avoid missing PVs

In analyze_storage, PVs are only discovered from per-object files under persistentvolumes/*.yaml, and persistentvolumes.yaml is explicitly skipped (Lines 137–138). On many must-gather captures, only the aggregated persistentvolumes.yaml List exists, so this will report “No PersistentVolumes found” even when PVs are present.

You already handle kind: List for PVCs; a similar fallback for PVs would make this more robust. For example:

-    for pattern in pv_patterns:
-        for pv_file in base_path.glob(pattern):
-            if pv_file.name == 'persistentvolumes.yaml':
-                continue
-            pv = parse_yaml_file(pv_file)
-            if pv and pv.get('kind') == 'PersistentVolume':
-                pvs.append(format_pv(pv))
+    for pattern in pv_patterns:
+        for pv_file in base_path.glob(pattern):
+            if pv_file.name == 'persistentvolumes.yaml':
+                # Aggregated List
+                pv_doc = parse_yaml_file(pv_file)
+                if pv_doc and pv_doc.get('kind') == 'List':
+                    for item in pv_doc.get('items', []):
+                        if item.get('kind') == 'PersistentVolume':
+                            pvs.append(format_pv(item))
+                continue
+            pv = parse_yaml_file(pv_file)
+            if pv and pv.get('kind') == 'PersistentVolume':
+                pvs.append(format_pv(pv))

This keeps current behavior but covers the common aggregated case too.

Also applies to: 191-208


200-207: Optional: drop constant f-strings in SUMMARY for style

The SUMMARY prints use f-strings with no interpolation (e.g., Line 201: print(f"SUMMARY")), which Ruff flags as F541. You can switch them to plain strings without changing behavior:

-    print(f"\n{'='*80}")
-    print(f"SUMMARY")
+    print("\n" + "=" * 80)
+    print("SUMMARY")

Purely cosmetic, but it keeps the analyzer scripts lint-clean.

plugins/must-gather/skills/must-gather-analyzer/scripts/analyze_nodes.py (1)

152-173: Consider supporting aggregated nodes.yaml as a fallback source

analyze_nodes only looks at per-node YAML files and explicitly skips nodes.yaml (Lines 163–164). On clusters where must-gather only includes the aggregated nodes.yaml List, this will result in “No resources found.”

Mirroring the PVC/PV pattern, you could treat nodes.yaml specially:

  • If per-node files are found, keep current behavior.
  • If not, fall back to parsing nodes.yaml as a List and iterating items.

This would make the script more resilient to different must-gather layouts while retaining the existing deduplication and sorting logic.

plugins/must-gather/README.md (2)

26-35: Add language specifiers to improve documentation rendering.

The command and output examples would benefit from language specifiers.

Apply this diff:

-```bash
+```bash
 ./analyze_clusterversion.py <must-gather-path>

Output format matches oc get clusterversion:
- +text
NAME VERSION AVAILABLE PROGRESSING SINCE STATUS


---

`47-56`: **Add language specifiers to code blocks.**

Add specifiers for better rendering.


Apply this diff:

```diff
-```bash
+```bash
 ./analyze_clusteroperators.py <must-gather-path>

Output format matches oc get clusteroperators:
- +text
NAME VERSION AVAILABLE PROGRESSING DEGRADED SINCE MESSAGE


</blockquote></details>
<details>
<summary>plugins/config/README.md (1)</summary><blockquote>

`114-116`: **Code block language specification.**

While the status line example here is output (not executable code), markdown linters require a language specifier. Use `` ```text `` to satisfy the linter and clarify this is example output.



```diff
-```
+```text
 v1.2.3 | Sonnet 4.5 | main | default | I would like to contribute ~/.clau...
-```
+```text
plugins/must-gather/skills/must-gather-analyzer/SKILL.md (3)

1-11: Add language specification to frontmatter code block.

Line 10 is a bare code block in the triggers section that should be marked as plain text or removed from the code fence.

-Triggers: "analyze must-gather", "check cluster health", "operator status", "pod issues",
-  "node status", "failing pods", "degraded operators", "cluster problems", "crashlooping",
-  "network issues", "etcd health", "analyze clusteroperators", "analyze pods", "analyze nodes"
+List of trigger phrases for this skill (moved from code block for better readability)

Alternatively, if keeping a code block, wrap with backticks and language:

triggers: analyze must-gather, check cluster health, operator status, pod issues, ...


135-135: Wrap bare URL in markdown link syntax.

Line 135 contains a bare URL which violates MD034. Wrap it in markdown link format: [text](url).

-- If they provide the root directory, look for the subdirectory with the hash name
+- If they provide the root directory, look for the [subdirectory with the hash name](https://example.com/docs)

If this refers to a specific resource, provide the actual URL; otherwise, remove or contextualize.


46-85: Add language specifications to code blocks.

Multiple code blocks lack language specifications (MD040). Update code fences to include language:

  • Bash commands → ```bash
  • JSON output → ```json
  • Plain output → ```text

Examples:

-```
+```bash
 ./scripts/analyze_clusterversion.py <must-gather-path>
-```
+```bash

This will improve syntax highlighting and satisfy markdown linting.

plugins/jira/skills/create-bug/SKILL.md (1)

55-78: Add language specifications to code blocks throughout.

Multiple code blocks lack language specifications (MD040). Update all fences to include language:

  • Python/code snippets → ```python
  • Bash commands → ```bash
  • Plain text → ```text
-```
+```
 Description of problem:
 <Clear, detailed description of the issue>

Apply this pattern consistently across lines 55, 69, 82, 91, 114, 131, 151, 165, 188, 361, 426, 448, 469, 490, 534.

plugins/openshift/README.md (1)

66-135: Add language specifications to code blocks.

Multiple code blocks lack language specifications (MD040). Update all bash command blocks to include ```bash marker:

-```
+```bash
 # Bump to latest version
 /openshift:bump-deps k8s.io/api
-```
+```bash

Apply this at lines 73, 115, 121, 125, 130, 145, 151, 153, 183, 185, 189, 191, 207, 209, 212, 215, 239, 244, 256, 281, 289.

plugins/olm/commands/list.md (1)

10-113: Add language specifications to code blocks.

Multiple code blocks lack language specifications (MD040). Update to include language markers:

-```
+```bash
 /olm:list [namespace] [--all-namespaces]
-```
+```bash

Apply this pattern to other code blocks at lines 46, and output blocks at line 79 (use ```text).

plugins/jira/commands/create.md (1)

439-445: Clarify fictional API key in anti-pattern example.

Line 442 contains a pattern that resembles a real API key format (sk_live_abc123xyz). While this is in an anti-pattern section (documenting what NOT to do), consider using a more obviously fictional placeholder format to avoid any ambiguity, such as:

- Export API_KEY=sk_live_abc123xyz
+ Export API_KEY=sk_live_xxxxx_REDACTED

or simply use the suggested mitigation format shown on line 444.

plugins/jira/skills/create-story/SKILL.md (1)

27-27: Minor wording improvement: "speak with" or "discuss with" preferred over "talk with".

Line 27: Consider replacing "talking with stakeholders" with "speaking with stakeholders" or "discussing with stakeholders" for more formal tone.

scripts/build-website.py (3)

41-57: Narrow broad except Exception in helpers

Catching bare Exception in get_plugin_commands and get_plugin_skills can hide real bugs and trips BLE001. It’s probably enough to handle filesystem/encoding issues explicitly and let other errors surface.

Consider something like:

-    for cmd_file in sorted(commands_dir.glob("*.md")):
-        try:
-            content = cmd_file.read_text()
+    for cmd_file in sorted(commands_dir.glob("*.md")):
+        try:
+            content = cmd_file.read_text()
             frontmatter = parse_frontmatter(content)
             synopsis = extract_synopsis(content)
@@
-        except Exception as e:
-            print(f"Error processing {cmd_file}: {e}")
+        except (OSError, UnicodeError) as e:
+            print(f"Error reading {cmd_file}: {e}")
@@
-        try:
-            content = skill_file.read_text()
+        try:
+            content = skill_file.read_text()
             frontmatter = parse_frontmatter(content)
@@
-        except Exception as e:
-            print(f"Error processing {skill_file}: {e}")
+        except (OSError, UnicodeError) as e:
+            print(f"Error reading {skill_file}: {e}")

Please rerun Ruff/CI after tightening the exception types to ensure no other callers rely on the broader catch.

Also applies to: 67-88


96-123: Remove unused readme and unused import

readme is read but never used, and os is imported but unused, which Ruff flags (F841) and adds noise.

You can simplify:

-import os
@@
-        readme_path = plugin_path / "README.md"
-        readme = ""
-        if readme_path.exists():
-            readme = readme_path.read_text()
-
         plugin_data = {
             "name": plugin_info["name"],
             "description": plugin_info["description"],
             "version": plugin_metadata.get("version", "unknown"),
             "commands": commands,
             "skills": skills,
-            "has_readme": readme_path.exists()
+            "has_readme": (plugin_path / "README.md").exists()
         }

This keeps behavior the same while cleaning up the lints.

After this change, please run Ruff or your CI to confirm all style checks pass.

Also applies to: 125-135, 145-153


1-1: Align shebang with how the script is invoked

Ruff notes a shebang on a non-executable file (EXE001). Either make the file executable in git (chmod +x) if you intend to run it directly, or drop the shebang if it’s always invoked as python3 scripts/build-website.py.

Please choose the convention that matches your Makefile/CI usage and re-run the linter.

plugins/openshift/commands/bump-deps.md (1)

1-422: Fix markdownlint issues (code fence languages, list indent, bare URLs)

The content reads well, but markdownlint is right about a few mechanical issues:

  • Many fenced code blocks lack a language (MD040).
  • Some nested list items are over-indented (MD007).
  • A couple of bare URLs appear in text (MD034).

Suggested patterns:

-```
-/openshift:bump-deps <dependency> [version] [--create-jira] [--create-pr]
-```
+```bash
+/openshift:bump-deps <dependency> [version] [--create-jira] [--create-pr]
+```
@@
-   ```
+   ```text
    Analyzing dependency: k8s.io/api
@@
--   Jira: https://issues.redhat.com/browse/OCPBUGS-12345
+-   Jira: [OCPBUGS-12345](https://issues.redhat.com/browse/OCPBUGS-12345)

Applying that pattern across the doc (bash/text where appropriate, and standard 2‑space list nesting) should make markdownlint happy without changing semantics.

After updating fences and links, please rerun markdownlint to ensure all warnings are resolved.

.claudelint-custom.py (2)

55-61: Prefer sys.executable over hard-coded "python3" in subprocess calls

Using a literal "python3" plus a partial path triggers the S603/S607 warnings and can be brittle in non-standard environments. The script path itself is already controlled.

You can make this more portable:

+import sys
@@
-            result = subprocess.run(
-                ["python3", str(script_path)],
+            result = subprocess.run(
+                [sys.executable, str(script_path)],
@@
-                result = subprocess.run(
-                    ["python3", str(website_script_path)],
+                result = subprocess.run(
+                    [sys.executable, str(website_script_path)],

This keeps the trust model the same but matches the interpreter actually running claudelint.

Please confirm this still matches how your CI invokes Python (e.g., virtualenv vs system Python) before merging.

Also applies to: 75-81


120-133: Consider narrowing or documenting the broad except Exception

The outer except Exception as e ensures the rule never crashes, but it also hides unexpected errors behind a generic violation, which BLE001 flags.

Two options:

  • Narrow to expected failures (e.g. OSError, subprocess.SubprocessError) and let truly unexpected exceptions surface, or
  • Keep the broad catch but add a brief comment explaining why it’s intentional.

Example for the first approach:

-        except subprocess.TimeoutExpired:
+        except subprocess.TimeoutExpired:
@@
-        except Exception as e:
+        except (OSError, subprocess.SubprocessError, ValueError) as e:
             violations.append(
                 self.violation(
                     f"Error checking files up-to-date status: {e}",
                     file_path=plugins_md_path
                 )
             )

Either way, making the intent explicit will help future maintainers and lint tooling.

If you tighten the exception types, please run claudelint against a repo with a broken generator to ensure the failure mode is still acceptable.

docs/data.json (1)

463-465: Clarify must-gather skill description

The Must-Gather Analyzer skill description is just "|", which looks accidental and will surface oddly in the marketplace UI and docs.

Consider replacing it with a short, meaningful description (or leaving it empty/null and handling that case in the UI) so users understand what this skill does.

scripts/generate_plugin_docs.py (1)

54-61: Align get_plugin_info’s type hints and behavior

get_plugin_info can return None (when .claude-plugin/plugin.json is missing), but the signature currently advertises PluginInfo. Callers correctly handle a falsy value, yet the annotation is misleading.

Also, generate_plugin_docs only includes plugins that have at least one command (if plugin_info and plugin_info.commands:), which seems intentional but is a behavioral constraint worth keeping explicit.

Consider:

-from typing import Dict, List, Tuple
+from typing import Dict, List, Tuple, Optional
...
-def get_plugin_info(plugin_dir: Path) -> PluginInfo:
+def get_plugin_info(plugin_dir: Path) -> Optional[PluginInfo]:

and optionally add a brief docstring note in generate_plugin_docs that command-less plugins are intentionally omitted from PLUGINS.md.

Also applies to: 65-69, 98-105

plugins/must-gather/skills/must-gather-analyzer/scripts/analyze_clusterversion.py (2)

159-159: Clean up f-strings without placeholders and unused variable

Ruff’s F541/F841 hints here are accurate and easy to address:

  • Lines 159, 177, 196: f-strings without any {} interpolations.
  • Line 193: image is assigned but never used.

A minimal tidy-up:

-    print(f"\nCONDITIONS:")
+    print("\nCONDITIONS:")
@@
-        print(f"\nUPDATE HISTORY (last 5):")
+        print("\nUPDATE HISTORY (last 5):")
@@
-            version = update.get('version', 'unknown')
-            image = update.get('image', '')
-            print(f"  {i+1}. {version}")
+            version = update.get('version', 'unknown')
+            print(f"  {i+1}. {version}")
@@
-    elif available_updates is None:
-        print(f"\nAVAILABLE UPDATES: Unable to retrieve updates")
+    elif available_updates is None:
+        print("\nAVAILABLE UPDATES: Unable to retrieve updates")

This keeps behavior identical while satisfying the linter.

Also applies to: 177-177, 193-193, 196-196


15-24: Narrow overly broad exception handlers and remove unused variables

The bare except Exception handlers in parse_clusterversion (lines 23–24) and calculate_duration (lines 54–55) catch unintended errors and complicate debugging. Additionally, the image variable is assigned but never used in two places (lines 188 and 198).

Tighten exception handling to expected failure modes and remove unused assignments:

 import yaml
+from yaml import YAMLError
 from pathlib import Path
 from datetime import datetime
 from typing import Dict, Any, Optional
...
 def parse_clusterversion(file_path: Path) -> Optional[Dict[str, Any]]:
     """Parse the clusterversion YAML file."""
     try:
         with open(file_path, 'r') as f:
             doc = yaml.safe_load(f)
             if doc and doc.get('kind') == 'ClusterVersion':
                 return doc
-    except Exception as e:
+    except (OSError, YAMLError) as e:
         print(f"Warning: Failed to parse {file_path}: {e}", file=sys.stderr)
     return None

 def calculate_duration(timestamp_str: str) -> str:
     """Calculate duration from timestamp to now."""
     try:
         ts = datetime.fromisoformat(timestamp_str.replace('Z', '+00:00'))
         now = datetime.now(ts.tzinfo)
         delta = now - ts

         days = delta.days
         hours = delta.seconds // 3600
         minutes = (delta.seconds % 3600) // 60

         if days > 0:
             return f"{days}d"
         elif hours > 0:
             return f"{hours}h"
         elif minutes > 0:
             return f"{minutes}m"
         else:
             return "<1m"
-    except Exception:
+    except ValueError:
         return ""

Also remove unused image variables at lines 188 and 198.

PyYAML documents that parsing/processing errors are raised as yaml.YAMLError (or its subclasses like ScannerError, ParserError, MarkedYAMLError), so catching yaml.YAMLError is the appropriate broad base to handle errors from yaml.safe_load.

docs/index.html (2)

564-581: Fix potential race between data loading and hash-based deep links

handleHashChange is bound to window.load, but it may run before loadData() has finished populating allPlugins, so a direct link like index.html#config can fail to open the plugin modal on first load.

Call handleHashChange() once after plugins have loaded, e.g.:

 async function loadData() {
     try {
         const response = await fetch('data.json');
         const data = await response.json();
         allPlugins = data.plugins;
@@
         document.getElementById('skill-count').textContent = totalSkills;
 
-        renderPlugins(allPlugins);
+        renderPlugins(allPlugins);
+        // Ensure hash-based deep links resolve once data is ready
+        handleHashChange();
     } catch (error) {
         console.error('Error loading data:', error);
     }
 }

This keeps the existing load/hashchange listeners but guarantees deep links work reliably on initial load.

Also applies to: 856-876


751-771: Defensively guard clipboard API usage

copyToClipboard assumes navigator.clipboard.writeText exists; in non-secure contexts (e.g., file:// or older browsers), navigator.clipboard can be undefined, leading to a synchronous TypeError before the Promise .catch is even reached.

Add a simple guard and fallback messaging:

 function copyToClipboard(text, event) {
     const button = event.currentTarget;
     const textSpan = button.querySelector('.copy-button-text');
     const originalText = textSpan.textContent;
 
-    navigator.clipboard.writeText(text).then(() => {
+    if (!navigator.clipboard || !navigator.clipboard.writeText) {
+        console.error('Clipboard API not available');
+        textSpan.textContent = 'Unavailable';
+        setTimeout(() => {
+            textSpan.textContent = originalText;
+        }, 2000);
+        return;
+    }
+
+    navigator.clipboard.writeText(text).then(() => {
         button.classList.add('copied');
         textSpan.textContent = 'Copied!';
@@
-    }).catch(err => {
+    }).catch(err => {
         console.error('Failed to copy:', err);

This keeps UX graceful even when the Clipboard API isn’t supported.

Comment on lines +1 to +18
# Available Plugins

This document lists all available Claude Code plugins and their commands in the ai-helpers repository.

- [Agendas](#agendas-plugin)
- [Ci](#ci-plugin)
- [Config](#config-plugin)
- [Doc](#doc-plugin)
- [Git](#git-plugin)
- [Hello World](#hello-world-plugin)
- [Jira](#jira-plugin)
- [Must Gather](#must-gather-plugin)
- [Olm](#olm-plugin)
- [Openshift](#openshift-plugin)
- [Prow Job](#prow-job-plugin)
- [Session](#session-plugin)
- [Utils](#utils-plugin)
- [Yaml](#yaml-plugin)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix heading level hierarchy.

Line 5-18 creates a table of contents with links. Line 20 starts the first plugin section with ### Agendas Plugin (h3), but after an h1 title (line 1), it should be h2. This violates MD001 (heading levels should only increment by one level at a time).

-# Available Plugins
+# Available Plugins
 
 This document lists all available Claude Code plugins and their commands in the ai-helpers repository.

Then update all plugin section headers to h2:

-### Agendas Plugin
+## Agendas Plugin

Apply this change to all plugin section headers (Agendas, Ci, Config, Doc, Git, etc.).

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In PLUGINS.md lines 1 to 18, the table of contents is under an H1 title but the
first plugin section starts at H3 (### Agendas Plugin), violating MD001; change
all plugin section headers (Agendas, Ci, Config, Doc, Git, Hello World, Jira,
Must Gather, Olm, Openshift, Prow Job, Session, Utils, Yaml) from H3 to H2
(replace "###" with "##") so each plugin section directly follows the H1 with a
single-level increment, and update any corresponding internal anchors if needed
to match the new header levels.

See [plugins/agendas/README.md](plugins/agendas/README.md) for detailed documentation.

### Ci Plugin

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix typo: "Miscellaenous" → "Miscellaneous".

Line 30 contains a spelling error flagged by LanguageTool.

-Miscellaenous tools for working with OpenShift CI
+Miscellaneous tools for working with OpenShift CI
📝 Committable suggestion

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

Suggested change
Miscellaneous tools for working with OpenShift CI
🧰 Tools
🪛 LanguageTool

[grammar] ~30-~30: Ensure spelling is correct
Context: ...detailed documentation. ### Ci Plugin Miscellaenous tools for working with OpenShift CI **...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🤖 Prompt for AI Agents
In PLUGINS.md around line 30, the word "Miscellaenous" is misspelled; replace it
with the correct spelling "Miscellaneous" (ensure casing matches surrounding
headings) and run a quick spell-check to confirm no other typos remain.

input=$(cat)

# Variables
TARGET_DIR="${TMPDIR:-/tmp}/claude-sessions"
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Ensure secure permissions for prompt storage directory.

The current implementation stores prompts in ${TMPDIR:-/tmp}/claude-sessions without explicitly setting restrictive permissions. Prompts may contain sensitive information (API keys, internal details, etc.), and the directory/files could be readable by other users on multi-user systems.

Apply this diff to use a user-specific directory with secure permissions:

-# Variables
-TARGET_DIR="${TMPDIR:-/tmp}/claude-sessions"
+# Variables - use user-specific directory with secure permissions
+TARGET_DIR="${HOME}/.claude/sessions"
+
+# Ensure directory exists with restrictive permissions
+mkdir -p "$TARGET_DIR"
+chmod 700 "$TARGET_DIR"

And update line 24-27:

-# Verify target folder exists
-mkdir -p "$TARGET_DIR"
-
 # Append to session-specific file
 echo "$PROMPT_SINGLE_LINE" >> "$TARGET_DIR/prompts-${SESSION_ID}.txt"
+chmod 600 "$TARGET_DIR/prompts-${SESSION_ID}.txt"

This ensures:

  • Prompts are stored in a user-specific location (~/.claude/sessions)
  • Directory has 0700 permissions (owner read/write/execute only)
  • Prompt files have 0600 permissions (owner read/write only)
  • No external dependencies required

Based on past review comments, the contributor noted wanting to avoid dependencies, and this solution maintains that goal while improving security.

Also applies to: 24-27

🤖 Prompt for AI Agents
In plugins/config/scripts/session-prompt-hook.sh around lines 9 and 24-27, the
script currently uses TARGET_DIR="${TMPDIR:-/tmp}/claude-sessions" and does not
set secure permissions; change TARGET_DIR to a user-specific directory like
"${HOME:-$USERPROFILE}/.claude/sessions", ensure the directory is created with
mkdir -p and explicit 0700 permissions (or set umask and then chmod 0700), and
when writing prompt files create them with restrictive permissions (use
redirection after setting umask 077 or use touch/chmod to 0600) so prompt files
are owner read/write only; avoid external dependencies and keep use of POSIX
shell builtins only.

git:branch-cleanup

## Synopsis
```
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add bash language specifier to code blocks.

Multiple code blocks lack language tags. Use `bash` consistently for shell command examples throughout the file to enable proper syntax highlighting in generated documentation.

Also applies to: 115-115, 119-119, 149-149, 153-153, 168-168, 172-172, 184-184, 188-188

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In plugins/git/commands/branch-cleanup.md around lines 10, 115, 119, 149, 153,
168, 172, 184 and 188, several fenced code blocks are missing a language
specifier; update each triple-backtick fence to use ```bash so all shell/command
examples include the bash language tag for proper syntax highlighting in
generated docs. Ensure every code block that contains shell commands is
consistently marked with bash and leave other non-shell blocks unchanged.

- Protected branches (main, master, develop, etc.)
- Branches with unmerged commits (unless explicitly overridden)

The spec sections is inspired by https://man7.org/linux/man-pages/man7/man-pages.7.html#top_of_page
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Wrap bare URL in markdown link syntax.

Line 25 contains a bare URL that should be formatted as a proper markdown link:

-The spec sections is inspired by https://man7.org/linux/man-pages/man7/man-pages.7.html#top_of_page
+The spec section is inspired by [Linux man-pages](https://man7.org/linux/man-pages/man7/man-pages.7.html#top_of_page)

Note: Also consider fixing the typo "spec sections is" → "spec section is".

📝 Committable suggestion

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

Suggested change
The spec sections is inspired by https://man7.org/linux/man-pages/man7/man-pages.7.html#top_of_page
The spec section is inspired by [Linux man-pages](https://man7.org/linux/man-pages/man7/man-pages.7.html#top_of_page)
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

25-25: Bare URL used

(MD034, no-bare-urls)

🤖 Prompt for AI Agents
In plugins/git/commands/branch-cleanup.md around line 25, the sentence contains
a bare URL and a typo ("spec sections is"); convert the bare URL into proper
Markdown link syntax (e.g.
[man-pages](https://man7.org/linux/man-pages/man7/man-pages.7.html#top_of_page))
and correct the text to "spec section is" so the line reads with a linked URL
and the fixed grammar.

## Commands

### Operator Management Commands

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add language identifiers to code blocks.

Lines 32 and 196 contain fenced code blocks without language identifiers. These should be tagged as bash for CLI examples.

Also applies to: 196-196

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

32-32: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
plugins/olm/README.md lines 32 and 196: the fenced code blocks at these lines
are missing language identifiers; update each triple-backtick fence to specify
"bash" (```bash) so the CLI examples are properly highlighted and parsed as
shell commands.

openshift:create-cluster

## Synopsis
```
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add language specifiers to code blocks.

Multiple code blocks lack language identifiers. Use `bash` for shell examples and `yaml` for YAML configurations to enable proper syntax highlighting in generated documentation.

Also applies to: 73-73, 132-132, 226-226, 263-263, 354-354, 359-359, 377-377, 406-406, 412-412, 417-417

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In plugins/openshift/commands/create-cluster.md around lines 10, 73, 132, 226,
263, 354, 359, 377, 406, 412 and 417, several fenced code blocks are missing
language specifiers; edit each opening triple-backtick to include the
appropriate language (use ```bash for shell/CLI examples and ```yaml for YAML
snippets) so syntax highlighting is enabled, and verify the closing
triple-backticks remain unchanged.

Before using this command, ensure you have:

1. **OpenShift CLI (`oc`)**: Required to extract the installer from the release image
- Install from: https://mirror.openshift.com/pub/openshift-v4/clients/ocp/
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Wrap bare URLs in markdown link syntax.

Several URLs should be formatted as proper markdown links for accessibility and correct rendering. For example:

- Install from: https://mirror.openshift.com/pub/openshift-v4/clients/ocp/
+ Install from: [OpenShift Clients](https://mirror.openshift.com/pub/openshift-v4/clients/ocp/)

- Download from https://console.redhat.com/openshift/install/pull-secret
+ Download from [Red Hat Console](https://console.redhat.com/openshift/install/pull-secret)

Apply consistent markdown link formatting throughout the file (lines 51, 260, 434, 451, 467, 468).

Also applies to: 260-260, 434-434, 451-451, 467-467, 468-468

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

51-51: Bare URL used

(MD034, no-bare-urls)

🤖 Prompt for AI Agents
In plugins/openshift/commands/create-cluster.md around lines 51, 260, 434, 451,
467 and 468, there are bare URLs that must be converted to markdown link syntax;
replace each plain URL with a markdown link like [label](https://example) using
an appropriate short descriptive label (e.g., "OpenShift clients mirror" for
https://mirror.openshift.com/pub/openshift-v4/clients/ocp/) and apply the same
link formatting consistently for the other listed lines so all URLs render
properly and are accessible.

openshift:destroy-cluster

## Synopsis
```
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add language specifiers to code blocks.

Multiple code blocks lack language identifiers. Use `bash` for shell commands and `yaml` for YAML output examples to enable proper syntax highlighting in generated documentation.

Also applies to: 89-89, 147-147, 202-202, 209-209, 230-230, 270-270, 279-279, 294-294, 300-300, 305-305

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In plugins/openshift/commands/destroy-cluster.md around line 10 (and also at
lines 89, 147, 202, 209, 230, 270, 279, 294, 300, 305), several fenced code
blocks are missing language specifiers; update each fence to include the
appropriate language (use ```bash for shell/CLI examples and ```yaml for YAML
output/examples) so syntax highlighting is enabled, ensuring you only change the
opening triple-backtick lines to add the language token and leave the block
contents intact.

## See Also

- `/openshift:create-cluster` - Create a new OCP cluster
- OpenShift Documentation: https://docs.openshift.com/container-platform/latest/installing/
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Wrap bare URL in markdown link syntax.

Line 355 contains a bare URL:

- OpenShift Documentation: https://docs.openshift.com/container-platform/latest/installing/
+ [OpenShift Documentation](https://docs.openshift.com/container-platform/latest/installing/)
📝 Committable suggestion

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

Suggested change
- OpenShift Documentation: https://docs.openshift.com/container-platform/latest/installing/
- [OpenShift Documentation](https://docs.openshift.com/container-platform/latest/installing/)
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

355-355: Bare URL used

(MD034, no-bare-urls)

🤖 Prompt for AI Agents
In plugins/openshift/commands/destroy-cluster.md at line 355, the OpenShift
documentation URL is a bare link; replace it with markdown link syntax by
wrapping the URL with descriptive link text (for example: [OpenShift
Documentation](https://docs.openshift.com/container-platform/latest/installing/))
so the reference is rendered as a proper clickable link.

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

Labels

needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. ok-to-test Indicates a non-member PR verified by an org member that is safe to test.

Projects

None yet

Development

Successfully merging this pull request may close these issues.