Skip to content

t008.1: Core plugin structure + agent loader#1138

Merged
marcusquinn merged 3 commits intomainfrom
feature/t008.1
Feb 11, 2026
Merged

t008.1: Core plugin structure + agent loader#1138
marcusquinn merged 3 commits intomainfrom
feature/t008.1

Conversation

@marcusquinn
Copy link
Owner

@marcusquinn marcusquinn commented Feb 11, 2026

Summary

Core plugin structure and agent loader for the aidevops framework (t008.1).

What's New

  • plugin-loader-helper.sh — Shell-based agent loader with 8 commands: discover, load, unload, validate, agents, hooks, index, status
  • plugin.json manifest format — Plugins can declare agents, lifecycle hooks, scripts, dependencies, and minimum version requirements
  • Lifecycle hooks — init (install/update), load (session start), unload (disable/remove) with environment variable injection
  • CLI integration — Hooks run automatically on aidevops plugin add/enable/disable/remove
  • Updated plugin templateaidevops plugin init now scaffolds manifest + hook scripts
  • Subagent index integrationplugin-loader-helper.sh index generates TOON entries for plugin agents

Design Decisions

  • Manifest is optional — plugins without plugin.json fall back to directory scanning for backward compatibility
  • Hooks are discovered by convention (scripts/on-{hook}.sh) or explicit manifest declaration
  • Agent loading uses manifest agents array when available, otherwise parses YAML frontmatter from .md files
  • Fixed pre-existing SC2115 ShellCheck warnings in plugin disable/remove commands

Files Changed

File Change
.agents/scripts/plugin-loader-helper.sh New — core agent loader
.agents/templates/plugin-template/plugin.json New — manifest template
.agents/templates/plugin-template/scripts/on-init.sh New — init hook template
.agents/templates/plugin-template/scripts/on-load.sh New — load hook template
.agents/templates/plugin-template/scripts/on-unload.sh New — unload hook template
aidevops.sh Updated — hook integration in plugin commands, SC2115 fix
.agents/aidevops/plugins.md Updated — manifest format, loader, hooks docs
.agents/subagent-index.toon Updated — registered plugin-loader-helper.sh

Testing

  • ShellCheck zero violations on all new/modified .sh files
  • End-to-end test: created test plugin with manifest + hooks, verified discover/validate/load/agents/index/hooks/status commands
  • Verified aidevops plugin init scaffolding includes manifest and hook scripts with correct placeholder substitution

Ref #1137

Summary by CodeRabbit

  • New Features

    • Added plugin lifecycle hooks (init/load/unload) integrated into enable/disable/remove flows.
    • Plugin scaffolding now includes a manifest and lifecycle hook scripts by default.
    • Introduced a CLI helper to discover, validate, load/unload plugins, list agents, build indexes, and show status (works with or without jq).
  • Documentation

    • Expanded plugin documentation with a full manifest example, field descriptions, lifecycle hooks, security considerations, and discovery workflow.
  • Chores

    • Provided template hook scripts for plugins.
    • Improved safety during removal with stricter path checks and clearer messages.

…alidation (t008.1)

Shell-based plugin loader that discovers installed plugins, validates
plugin.json manifests, loads agent definitions, manages lifecycle hooks
(init/load/unload), and generates TOON entries for the subagent-index.

Chose directory scanning fallback over manifest-only approach to maintain
backward compatibility with existing plugins that lack plugin.json.
- Add plugin.json manifest template with agents, hooks, and dependency fields
- Add lifecycle hook templates (on-init.sh, on-load.sh, on-unload.sh)
- Integrate hooks into aidevops.sh plugin add/enable/disable/remove commands
- Update plugins.md with manifest format, agent loader, and hooks documentation
- Update plugin init scaffolding to include manifest and hook scripts
- Fix ShellCheck: remove unused RESERVED_NAMESPACES, add SC2034 directives for template vars
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

Walkthrough

This pull request implements a comprehensive plugin lifecycle management system for the AI DevOps framework, adding manifest-driven plugin definition, lifecycle hooks (init/load/unload), and a plugin-loader helper script that handles plugin discovery, validation, agent loading, and hook execution. It also integrates lifecycle hooks into the main CLI and provides template scripts for plugins.

Changes

Cohort / File(s) Summary
Plugin Documentation & Indexing
.agents/aidevops/plugins.md, .agents/subagent-index.toon
Documents Plugin Manifest (plugin.json) specification with example manifests, field descriptions, agent loading priorities, hook lifecycle definitions, and security considerations. Updates TOON index to reference the new plugin-loader-helper script.
Plugin Loader Helper
.agents/scripts/plugin-loader-helper.sh
New comprehensive Bash utility providing logging, plugin discovery/validation, manifest parsing, agent loading/indexing (via Markdown frontmatter or filesystem), lifecycle hook execution (init/load/unload), and CLI command dispatch (discover, load, unload, validate, agents, hooks, index, status, help). Supports both manifest-driven and filesystem-based agent definitions with graceful jq fallback.
Lifecycle Hook Templates
.agents/templates/plugin-template/scripts/{on-init,on-load,on-unload}.sh
Adds three Bash hook scripts with strict error handling (set -euo pipefail), environment variable resolution for plugin_dir and namespace, starter templates for initialization, loading, and cleanup logic with commented examples for configuration and tool validation.
Main CLI Integration
aidevops.sh
Integrates plugin-loader-helper lifecycle hook invocation into cmd_plugin flow: runs init hook after enabling, unload hook before removing/disabling. Scaffolds plugin.json manifest and lifecycle scripts during plugin init. Adds path safety guard (${target_ns:?}) to prevent accidental empty-path deletions.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant aidevops.sh
    participant plugin-loader-helper.sh
    participant Plugin Manifest
    participant Lifecycle Hooks

    User->>aidevops.sh: cmd_plugin init <namespace>
    activate aidevops.sh
    aidevops.sh->>aidevops.sh: Scaffold plugin.json & scripts/
    aidevops.sh->>plugin-loader-helper.sh: plugin-loader-helper.sh hooks init
    deactivate aidevops.sh
    activate plugin-loader-helper.sh
    plugin-loader-helper.sh->>Plugin Manifest: Read plugin.json
    plugin-loader-helper.sh->>Lifecycle Hooks: Execute on-init.sh
    Lifecycle Hooks-->>plugin-loader-helper.sh: Hook complete
    plugin-loader-helper.sh-->>aidevops.sh: Return status
    deactivate plugin-loader-helper.sh

    User->>aidevops.sh: cmd_plugin enable <namespace>
    activate aidevops.sh
    aidevops.sh->>plugin-loader-helper.sh: plugin-loader-helper.sh hooks init
    plugin-loader-helper.sh->>Lifecycle Hooks: Execute on-init.sh
    Lifecycle Hooks-->>User: Initialization complete
    deactivate aidevops.sh

    User->>aidevops.sh: cmd_plugin remove <namespace>
    activate aidevops.sh
    aidevops.sh->>plugin-loader-helper.sh: plugin-loader-helper.sh hooks unload
    activate plugin-loader-helper.sh
    plugin-loader-helper.sh->>Lifecycle Hooks: Execute on-unload.sh
    Lifecycle Hooks-->>plugin-loader-helper.sh: Cleanup complete
    plugin-loader-helper.sh-->>aidevops.sh: Return status
    deactivate plugin-loader-helper.sh
    aidevops.sh->>aidevops.sh: Remove plugin directory
    aidevops.sh-->>User: Plugin removed
    deactivate aidevops.sh
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • t008: aidevops-opencode Plugin #501: Directly addresses "core plugin structure + agent loader" by implementing manifest-driven plugin definitions, lifecycle hooks, and comprehensive plugin loader helper with agent discovery and indexing capabilities.

Possibly related PRs

Poem

🔌 Plugins now bloom with hooks so grand,

Init, load, and unload planned,

Manifest wisdom, scripts aligned,

Helper tools of DevOps kind! ⚙️✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the primary additions: a core plugin structure framework and an agent loader mechanism, which aligns with the main changes across all modified files.
Docstring Coverage ✅ Passed Docstring coverage is 86.36% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/t008.1

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

❤️ Share

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

@github-actions
Copy link

🔍 Code Quality Report

�[0;35m[MONITOR]�[0m Code Review Monitoring Report

�[0;34m[INFO]�[0m Latest Quality Status:
SonarCloud: 0 bugs, 0 vulnerabilities, 47 code smells

�[0;34m[INFO]�[0m Recent monitoring activity:
Wed Feb 11 15:03:17 UTC 2026: Code review monitoring started
Wed Feb 11 15:03:18 UTC 2026: SonarCloud - Bugs: 0, Vulnerabilities: 0, Code Smells: 47

📈 Current Quality Metrics

  • BUGS: 0
  • CODE SMELLS: 47
  • VULNERABILITIES: 0

Generated on: Wed Feb 11 15:03:20 UTC 2026


Generated by AI DevOps Framework Code Review Monitoring

@marcusquinn marcusquinn marked this pull request as ready for review February 11, 2026 15:05
@github-actions
Copy link

🔍 Code Quality Report

�[0;35m[MONITOR]�[0m Code Review Monitoring Report

�[0;34m[INFO]�[0m Latest Quality Status:
SonarCloud: 0 bugs, 0 vulnerabilities, 47 code smells

�[0;34m[INFO]�[0m Recent monitoring activity:
Wed Feb 11 15:06:08 UTC 2026: Code review monitoring started
Wed Feb 11 15:06:09 UTC 2026: SonarCloud - Bugs: 0, Vulnerabilities: 0, Code Smells: 47

📈 Current Quality Metrics

  • BUGS: 0
  • CODE SMELLS: 47
  • VULNERABILITIES: 0

Generated on: Wed Feb 11 15:06:12 UTC 2026


Generated by AI DevOps Framework Code Review Monitoring

@gemini-code-assist
Copy link

Summary of Changes

Hello @marcusquinn, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the aidevops framework's plugin system by introducing a more robust and structured approach to plugin definition and management. It provides developers with a clear manifest format and lifecycle hooks, allowing for more controlled and automated plugin behavior, while maintaining backward compatibility for existing plugins. The changes streamline plugin development, integration, and operational management within the aidevops ecosystem.

Highlights

  • Core Plugin Structure: Introduced a new plugin.json manifest format for plugins to explicitly declare agents, lifecycle hooks, scripts, dependencies, and minimum version requirements, offering a structured way to define plugin capabilities.
  • Agent Loader Script: Added plugin-loader-helper.sh, a shell-based script providing 8 commands for managing plugins: discover, load, unload, validate, agents, hooks, index, and status, centralizing plugin operations.
  • Lifecycle Hooks: Implemented init, load, and unload lifecycle hooks that allow plugins to execute shell scripts at specific events (install/update, session start, disable/remove), with environment variable injection for context.
  • CLI Integration: Integrated lifecycle hooks into the aidevops plugin add/enable/disable/remove CLI commands, ensuring hooks run automatically at appropriate stages.
  • Enhanced Plugin Template: Updated the aidevops plugin init command to scaffold new plugins with the plugin.json manifest and example lifecycle hook scripts, streamlining new plugin development.
  • Flexible Agent Discovery: Designed the system to be backward compatible, allowing plugins without a plugin.json manifest to fall back to directory scanning and YAML frontmatter parsing for agent discovery.
  • Subagent Index Integration: Enabled plugin-loader-helper.sh index to generate TOON entries for plugin agents, facilitating their inclusion in the main subagent index.
Changelog
  • .agents/aidevops/plugins.md
    • Updated plugin structure documentation to include plugin.json and lifecycle hooks.
    • Added detailed documentation for the plugin.json manifest format and its fields.
    • Included a section explaining the plugin-loader-helper.sh agent loader commands and agent loading priority.
    • Documented the new lifecycle hooks (init, load, unload) and their use cases, along with available environment variables.
  • .agents/scripts/plugin-loader-helper.sh
    • Added a new shell script to manage plugin discovery, validation, agent loading, and lifecycle hooks.
    • Implemented commands for discover, load, unload, validate, agents, hooks, index, and status.
  • .agents/subagent-index.toon
    • Updated the script count in the TOON header from 73 to 74.
    • Added an entry for plugin-loader-helper.sh to the subagent index.
  • .agents/templates/plugin-template/plugin.json
    • Added a new template for the plugin.json manifest, including placeholders for plugin name, version, description, agents, and hooks.
  • .agents/templates/plugin-template/scripts/on-init.sh
    • Added a new template for the on-init.sh lifecycle hook script, with comments for common setup tasks.
  • .agents/templates/plugin-template/scripts/on-load.sh
    • Added a new template for the on-load.sh lifecycle hook script, with comments for session-specific setup.
  • .agents/templates/plugin-template/scripts/on-unload.sh
    • Added a new template for the on-unload.sh lifecycle hook script, with comments for cleanup tasks.
  • aidevops.sh
    • Integrated the init lifecycle hook to run when a plugin is added or enabled.
    • Integrated the unload lifecycle hook to run before a plugin's files are removed during disable or remove operations.
    • Applied ShellCheck fixes (SC2115) to rm -rf commands for improved safety.
Activity
  • The pull request introduces a new core plugin structure and agent loader, with detailed descriptions of new features, design decisions, and testing performed by the author.
  • No specific human review comments or interactions have been recorded yet for this pull request.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@sonarqubecloud
Copy link

@marcusquinn marcusquinn merged commit d2e23a4 into main Feb 11, 2026
9 of 10 checks passed
Copy link

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

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a robust plugin architecture with manifests and lifecycle hooks, which is a great enhancement for the framework's extensibility. The new plugin-loader-helper.sh script is comprehensive and the integration into aidevops.sh is well-handled. The documentation and template updates are also thorough.

My review focuses on adherence to the repository's shell scripting style guide and improving error visibility. The identified areas for improvement, concerning logging function duplication, regex for semver validation, and error suppression when running hooks, remain valid and will improve maintainability and debugging for plugin developers.

Comment on lines +40 to +62
log_info() {
local msg="$1"
echo -e "${BLUE:-}[plugin-loader]${NC:-} $msg"
return 0
}

log_success() {
local msg="$1"
echo -e "${GREEN:-}[OK]${NC:-} $msg"
return 0
}

log_warning() {
local msg="$1"
echo -e "${YELLOW:-}[WARN]${NC:-} $msg"
return 0
}

log_error() {
local msg="$1"
echo -e "${RED:-}[ERROR]${NC:-} $msg"
return 0
}

Choose a reason for hiding this comment

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

medium

These log_* functions duplicate the functionality of the print_* functions available from shared-constants.sh, which is sourced on line 27. The repository style guide advises against duplicating these functions to improve maintainability.

Please remove these local log_* functions and use the shared print_* functions instead. You can achieve the same output by prepending the prefix to the message, for example: print_info "[plugin-loader] Discovering plugins...".

References
  1. The style guide specifies that scripts should source shared-constants.sh for common functions like print_info and print_error, and explicitly states not to duplicate them (lines 18-19). The new log_* functions are duplicates of this functionality. (link)
  2. Rule: For standalone shell scripts, it is acceptable to duplicate simple, self-contained helper functions instead of introducing source dependencies. This comment is valid because the script plugin-loader-helper.sh already sources shared-constants.sh on line 27, meaning it is not a standalone script in the context of avoiding source dependencies. Therefore, the rationale for allowing duplication (maintaining script independence) does not apply, and the existing style guide advice against duplication for maintainability remains relevant.

fi

# Validate version format (semver-like)
if [[ -n "$version" ]] && [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then

Choose a reason for hiding this comment

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

medium

The current regex for semver validation does not allow for hyphens in the pre-release identifier (e.g., 1.0.0-beta-1), which is valid according to the SemVer specification. Please update the regex to include hyphens in the character class to ensure correct validation.

Suggested change
if [[ -n "$version" ]] && [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
if [[ -n "$version" ]] && [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then

fi

# Run init hook if available
run_hook "$target" "init" 2>/dev/null || true

Choose a reason for hiding this comment

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

medium

Suppressing stderr with 2>/dev/null can hide important error messages from the hook script, making debugging difficult. The repository style guide (line 50) discourages blanket suppression of errors. The || true guard is sufficient to prevent the main script from exiting on a hook failure.

Please remove the 2>/dev/null to allow hook errors to be visible. This also applies to lines 439, 458, and 471.

Suggested change
run_hook "$target" "init" 2>/dev/null || true
run_hook "$target" "init" || true
References
  1. The style guide states that 2>/dev/null is only acceptable when redirecting to log files, not for blanket suppression of errors (line 50). Suppressing stderr from hook scripts can hide important debugging information. (link)

# Run init hook via plugin-loader if available
local loader_script="$agents_dir/scripts/plugin-loader-helper.sh"
if [[ -f "$loader_script" ]]; then
bash "$loader_script" hooks "$namespace" init 2>/dev/null || true

Choose a reason for hiding this comment

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

medium

Suppressing stderr with 2>/dev/null can hide important error messages from the hook script, making debugging difficult. The repository style guide (line 50) discourages blanket suppression of errors. The || true guard is sufficient to prevent the main script from exiting on a hook failure.

Please remove the 2>/dev/null to allow hook errors to be visible. This applies to other similar calls in this file (lines 2378, 2401, 2433).

Suggested change
bash "$loader_script" hooks "$namespace" init 2>/dev/null || true
bash "$loader_script" hooks "$namespace" init || true
References
  1. The style guide states that 2>/dev/null is only acceptable when redirecting to log files, not for blanket suppression of errors (line 50). Suppressing stderr from hook scripts can hide important debugging information. (link)

@marcusquinn marcusquinn deleted the feature/t008.1 branch February 11, 2026 15:08
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: 4

Caution

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

⚠️ Outside diff range comments (2)
.agents/aidevops/plugins.md (1)

220-225: ⚠️ Potential issue | 🟡 Minor

Documentation inconsistency: hooks are now auto-executed on lifecycle events.

Line 223 states "Plugin scripts are NOT auto-executed; they must be explicitly invoked," but the new integration in aidevops.sh (lines 2242–2246, 2375–2379, 2398–2402, 2430–2434) auto-runs init/unload hooks on plugin add, enable, disable, and remove. This security note should be updated to reflect that lifecycle hooks are executed automatically, while other plugin scripts remain explicitly invoked.

aidevops.sh (1)

2296-2306: ⚠️ Potential issue | 🟠 Major

Missing lifecycle hooks in the update flow.

The documentation (plugins.md line 208) states the init hook runs on "Install, update, enable," but the update case here re-clones the plugin directory without invoking any lifecycle hooks. After rm -rf + git clone, neither the init nor load hook is called — unlike add and enable which both trigger init.

Consider adding the same hook invocation after a successful update:

Proposed fix
                 if git clone --branch "$branch_name" --depth 1 "$repo" "$clone_dir" 2>&1; then
                     rm -rf "$clone_dir/.git"
+                    # Run init hook after update
+                    local loader_script="$agents_dir/scripts/plugin-loader-helper.sh"
+                    if [[ -f "$loader_script" ]]; then
+                        bash "$loader_script" hooks "$ns" init 2>/dev/null || true
+                    fi
                     print_success "Plugin '$target' updated"

The same pattern should be applied inside the bulk-update loop (around line 2329).

🤖 Fix all issues with AI agents
In @.agents/scripts/plugin-loader-helper.sh:
- Around line 269-284: The version check currently reads current_version from
"$HOME/.aidevops/version" which doesn't exist; update the logic that sets
current_version to read the correct VERSION file used by the framework (use the
same source as VERSION_FILE/AGENTS_DIR used elsewhere) — replace the fallback
path with reading either "$HOME/Git/aidevops/VERSION" or "$AGENTS_DIR/VERSION"
(whichever matches the deployed environment), preserving the existing default
fallback of "0.0.0"; ensure the variables min_version and current_version and
the subsequent comparison logic in the plugin loader helper remain unchanged so
log_warning still triggers correctly when current_version is less than
min_version.
- Around line 413-441: The cmd_load function is incorrectly invoking the init
hook on every call; remove the run_hook "$target" "init" invocations from
cmd_load (both the single-target path and the bulk-load loop) so only the load
hook is run during session loads; keep the run_hook "$target" "load" calls
intact, and ensure any init invocation remains only in install/update/enable
flows (not in cmd_load) to match the documented plugin lifecycle.

In @.agents/subagent-index.toon:
- Line 90: Update the TOON header count to match actual entries: replace the
header token "TOON:scripts[74]" with "TOON:scripts[76]" so the declared script
count equals the 76 script entries present (lines following the header under the
TOON:scripts block).

In @.agents/templates/plugin-template/plugin.json:
- Around line 14-17: The subagent "name" field in plugin.json is too generic
("name": "example") and may collide with other plugins; update the "name"
property to a namespaced identifier that includes the package/namespace (e.g.,
use the same namespace token as the "file" field like "{{NAMESPACE}}/example" or
"{{NAMESPACE}}-example") so the subagent name is unique across shared indexes;
change the value of the "name" key in plugin.json accordingly.
🧹 Nitpick comments (1)
.agents/scripts/plugin-loader-helper.sh (1)

97-107: get_plugin_field lacks jq availability check unlike sibling functions.

get_enabled_namespaces and get_all_namespaces both guard against missing jq, but get_plugin_field directly calls jq without checking. The || echo "" on line 105 catches the failure, but it produces a stderr error message (suppressed by 2>/dev/null on the jq call itself). This works but is inconsistent with the defensive pattern used elsewhere.

Optional: add jq guard for consistency
 get_plugin_field() {
     local namespace="$1"
     local field="$2"
     if [[ ! -f "$PLUGINS_FILE" ]]; then
         return 0
     fi
+    if ! command -v jq &>/dev/null; then
+        return 0
+    fi
     jq -r --arg ns "$namespace" --arg f "$field" \

Comment on lines +269 to +284
# Validate min_version if present
local min_version
min_version=$(jq -r '.min_aidevops_version // empty' "$manifest" 2>/dev/null)
if [[ -n "$min_version" ]]; then
local current_version
current_version=$(cat "$HOME/.aidevops/version" 2>/dev/null || echo "0.0.0")
# Simple version comparison (major.minor only)
local min_major min_minor cur_major cur_minor
min_major=$(echo "$min_version" | cut -d. -f1)
min_minor=$(echo "$min_version" | cut -d. -f2)
cur_major=$(echo "$current_version" | cut -d. -f1)
cur_minor=$(echo "$current_version" | cut -d. -f2)
if [[ "$cur_major" -lt "$min_major" ]] || { [[ "$cur_major" -eq "$min_major" ]] && [[ "$cur_minor" -lt "$min_minor" ]]; }; then
log_warning "Plugin requires aidevops >= $min_version (current: $current_version)"
fi
fi
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 | 🟠 Major

Wrong version file path — version check will always fall back to 0.0.0.

Line 274 reads the current version from $HOME/.aidevops/version, but the framework stores its version at $HOME/Git/aidevops/VERSION (per VERSION_FILE in aidevops.sh line 26) or $AGENTS_DIR/VERSION (the deployed agents version). The file $HOME/.aidevops/version likely never exists, so current_version will always be "0.0.0", effectively making the min_aidevops_version check a no-op (it will always warn).

Proposed fix
     if [[ -n "$min_version" ]]; then
         local current_version
-        current_version=$(cat "$HOME/.aidevops/version" 2>/dev/null || echo "0.0.0")
+        current_version=$(cat "$AGENTS_DIR/VERSION" 2>/dev/null || echo "0.0.0")
🤖 Prompt for AI Agents
In @.agents/scripts/plugin-loader-helper.sh around lines 269 - 284, The version
check currently reads current_version from "$HOME/.aidevops/version" which
doesn't exist; update the logic that sets current_version to read the correct
VERSION file used by the framework (use the same source as
VERSION_FILE/AGENTS_DIR used elsewhere) — replace the fallback path with reading
either "$HOME/Git/aidevops/VERSION" or "$AGENTS_DIR/VERSION" (whichever matches
the deployed environment), preserving the existing default fallback of "0.0.0";
ensure the variables min_version and current_version and the subsequent
comparison logic in the plugin loader helper remain unchanged so log_warning
still triggers correctly when current_version is less than min_version.

Comment on lines +413 to +441
# Load all enabled plugin agents
cmd_load() {
local target="${1:-}"

if [[ -n "$target" ]]; then
if ! is_valid_plugin "$target"; then
log_error "Plugin '$target' not found or not registered"
return 1
fi

# Run init hook if available
run_hook "$target" "init" 2>/dev/null || true

local agents
agents=$(load_plugin_agents "$target")
if [[ -z "$agents" ]]; then
log_info "No agents found in plugin '$target'"
return 0
fi

log_success "Loaded agents from '$target':"
echo "$agents" | while IFS=$'\t' read -r name file desc model; do
printf " %-20s %-30s %s\n" "$name" "$file" "$desc"
done

# Run load hook if available
run_hook "$target" "load" 2>/dev/null || true
return 0
fi
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 | 🟠 Major

cmd_load incorrectly runs init hook on every invocation.

Lines 424 and 458 run run_hook "$target" "init" each time cmd_load is called. Per the documented semantics (plugins.md line 208), the init hook should run on "Install, update, enable" — not on every session load. The load hook (line 439/471) is the correct one for session-start loading.

Running init on every load could re-execute one-time setup logic (e.g., creating config directories, checking dependencies) unnecessarily, and diverges from what plugin authors will expect from the lifecycle contract.

Proposed fix — remove init hook calls from cmd_load
     if [[ -n "$target" ]]; then
         if ! is_valid_plugin "$target"; then
             log_error "Plugin '$target' not found or not registered"
             return 1
         fi

-        # Run init hook if available
-        run_hook "$target" "init" 2>/dev/null || true
-
         local agents
         agents=$(load_plugin_agents "$target")

And in the bulk-load loop:

     while IFS= read -r ns; do
         [[ -z "$ns" ]] && continue

-        # Run init hook
-        run_hook "$ns" "init" 2>/dev/null || true
-
         local agents
         agents=$(load_plugin_agents "$ns")
📝 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
# Load all enabled plugin agents
cmd_load() {
local target="${1:-}"
if [[ -n "$target" ]]; then
if ! is_valid_plugin "$target"; then
log_error "Plugin '$target' not found or not registered"
return 1
fi
# Run init hook if available
run_hook "$target" "init" 2>/dev/null || true
local agents
agents=$(load_plugin_agents "$target")
if [[ -z "$agents" ]]; then
log_info "No agents found in plugin '$target'"
return 0
fi
log_success "Loaded agents from '$target':"
echo "$agents" | while IFS=$'\t' read -r name file desc model; do
printf " %-20s %-30s %s\n" "$name" "$file" "$desc"
done
# Run load hook if available
run_hook "$target" "load" 2>/dev/null || true
return 0
fi
# Load all enabled plugin agents
cmd_load() {
local target="${1:-}"
if [[ -n "$target" ]]; then
if ! is_valid_plugin "$target"; then
log_error "Plugin '$target' not found or not registered"
return 1
fi
local agents
agents=$(load_plugin_agents "$target")
if [[ -z "$agents" ]]; then
log_info "No agents found in plugin '$target'"
return 0
fi
log_success "Loaded agents from '$target':"
echo "$agents" | while IFS=$'\t' read -r name file desc model; do
printf " %-20s %-30s %s\n" "$name" "$file" "$desc"
done
# Run load hook if available
run_hook "$target" "load" 2>/dev/null || true
return 0
fi
🤖 Prompt for AI Agents
In @.agents/scripts/plugin-loader-helper.sh around lines 413 - 441, The cmd_load
function is incorrectly invoking the init hook on every call; remove the
run_hook "$target" "init" invocations from cmd_load (both the single-target path
and the bulk-load loop) so only the load hook is run during session loads; keep
the run_hook "$target" "load" calls intact, and ensure any init invocation
remains only in install/update/enable flows (not in cmd_load) to match the
documented plugin lifecycle.

-->

<!--TOON:scripts[73]{name,purpose}:
<!--TOON:scripts[74]{name,purpose}:
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

🧩 Analysis chain

🏁 Script executed:

fd 'subagent-index.toon' -x wc -l {}

Repository: marcusquinn/aidevops

Length of output: 97


🏁 Script executed:

# Find and read the .agents/subagent-index.toon file
fd 'subagent-index.toon' -x head -200 {} | head -100

Repository: marcusquinn/aidevops

Length of output: 9005


🏁 Script executed:

# Get exact line count and extract the TOON:scripts header
fd 'subagent-index.toon' -x sh -c '
  echo "=== File Info ===" 
  wc -l "$1"
  echo ""
  echo "=== TOON:scripts Header ===" 
  grep -n "^<!--TOON:scripts" "$1"
  echo ""
  echo "=== Closing Tag ===" 
  grep -n "^-->" "$1" | head -1
  echo ""
  echo "=== Script Entry Count ===" 
  awk "/^<!--TOON:scripts/{start=NR; next} /^-->/{if(start) {count=NR-start-1; print \"Entries between lines \" start \"+1 and \" NR \"-1 = \" count; exit}}" "$1"
' _ {}

Repository: marcusquinn/aidevops

Length of output: 281


TOON script count is incorrect and requires correction.

The header declares TOON:scripts[74] on line 90, but the file contains 76 actual script entries (lines 91–166). Update the header to TOON:scripts[76] to maintain accurate metadata.

🤖 Prompt for AI Agents
In @.agents/subagent-index.toon at line 90, Update the TOON header count to
match actual entries: replace the header token "TOON:scripts[74]" with
"TOON:scripts[76]" so the declared script count equals the 76 script entries
present (lines following the header under the TOON:scripts block).

Comment on lines +14 to +17
"file": "{{NAMESPACE}}/example.md",
"name": "example",
"description": "Example subagent",
"model": "sonnet"
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

Namespace the example subagent name to avoid collisions.

Using "name": "example" can conflict with other plugins’ subagents in shared indexes. Prefer a namespaced name to keep it unique.

🔧 Suggested tweak
-      "name": "example",
+      "name": "{{NAMESPACE}}.example",
📝 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
"file": "{{NAMESPACE}}/example.md",
"name": "example",
"description": "Example subagent",
"model": "sonnet"
"file": "{{NAMESPACE}}/example.md",
"name": "{{NAMESPACE}}.example",
"description": "Example subagent",
"model": "sonnet"
🤖 Prompt for AI Agents
In @.agents/templates/plugin-template/plugin.json around lines 14 - 17, The
subagent "name" field in plugin.json is too generic ("name": "example") and may
collide with other plugins; update the "name" property to a namespaced
identifier that includes the package/namespace (e.g., use the same namespace
token as the "file" field like "{{NAMESPACE}}/example" or
"{{NAMESPACE}}-example") so the subagent name is unique across shared indexes;
change the value of the "name" key in plugin.json accordingly.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant