From d2a351a1319d68a117ccfc777c53bbbf65b1c76a Mon Sep 17 00:00:00 2001 From: mbanderas Date: Thu, 18 Jun 2026 13:28:08 +0100 Subject: [PATCH 1/2] Add Maestro: Costguard to Tools & Integrations Add the Costguard plugin listing (read-only CI/cron and cloud-spend cost auditor for Codex) with its bundle under plugins/mbanderas/costguard/ and entries in plugins.json and .agents/plugins/marketplace.json. Also fix two pre-existing alphabetical-order inversions in README.md (GrayMatter/Generative Media Skills; ScrapeGraph AI/Rust Reverse Engineering) so the alphabetical-check passes. Co-Authored-By: Claude Opus 4.8 (1M context) --- .agents/plugins/marketplace.json | 15 ++ README.md | 5 +- plugins.json | 10 + .../costguard/.codex-plugin/plugin.json | 30 +++ plugins/mbanderas/costguard/.codexignore | 22 ++ plugins/mbanderas/costguard/README.md | 36 +++ plugins/mbanderas/costguard/assets/icon.png | Bin 0 -> 35620 bytes .../costguard/skills/costguard/SKILL.md | 221 ++++++++++++++++++ 8 files changed, 337 insertions(+), 2 deletions(-) create mode 100644 plugins/mbanderas/costguard/.codex-plugin/plugin.json create mode 100644 plugins/mbanderas/costguard/.codexignore create mode 100644 plugins/mbanderas/costguard/README.md create mode 100644 plugins/mbanderas/costguard/assets/icon.png create mode 100644 plugins/mbanderas/costguard/skills/costguard/SKILL.md diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json index a635cd93..19a840fe 100644 --- a/.agents/plugins/marketplace.json +++ b/.agents/plugins/marketplace.json @@ -1139,6 +1139,21 @@ "description": "Generate compact first-pass repository briefings for coding agents before deeper exploration.", "icon": "./plugins/Rothschildiuk/context-pack/skills/context-pack/assets/context-pack-small.svg" }, + { + "name": "costguard", + "displayName": "Maestro: Costguard", + "source": { + "source": "local", + "path": "./plugins/mbanderas/costguard" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Tools & Integrations", + "description": "Cost auditor for Codex that flags CI/cron and cloud-spend waste via read-only provider checks, then previews and applies surgical CI workflow fixes locally without writing to provider accounts or pushing git.", + "icon": "./plugins/mbanderas/costguard/assets/icon.png" + }, { "name": "dataproduct-builder-dbt", "displayName": "Data Product Builder for dbt", diff --git a/README.md b/README.md index 63d31fb5..e3eba208 100644 --- a/README.md +++ b/README.md @@ -172,8 +172,8 @@ Third-party plugins built by the community. [PRs welcome](#contributing)! - [Flaky Detector](./plugins/mturac/flaky-detector) - Run a test command N times, report per-test flakiness %. - [Frappe Agent](https://github.com/Dkm0315/frappe-agent) - Frappe and ERPNext coding, customization, bench, and review intelligence for Codex. - [GCF Proxy](https://github.com/blackwell-systems/gcf-codex-plugin) - Save 71% on MCP tool call tokens by wrapping any server with GCF encoding, with session stats hook and setup skill. -- [GrayMatter](https://github.com/ValkyrLabs/GrayMatter) - Durable memory and shared graph state for Codex and OpenClaw agents, with live ValkyrAI schema awareness. - [Generative Media Skills](https://github.com/SamurAIGPT/Generative-Media-Skills) - 13 skills for image, video, and audio generation using 100+ models - FLUX, Midjourney v7, Veo3, Kling 3.0, Suno, and HunyuanVideo via muapi.ai. +- [GrayMatter](https://github.com/ValkyrLabs/GrayMatter) - Durable memory and shared graph state for Codex and OpenClaw agents, with live ValkyrAI schema awareness. - [HOL Guard Plugin](https://github.com/hashgraph-online/hol-guard-plugin) - AI antivirus workflow for Codex, Claude Code, Cursor, Gemini, OpenCode, MCP servers, skills, and plugin release checks with local approvals and receipts. - [HOTL Plugin](https://github.com/yimwoo/hotl-plugin) - Human-on-the-Loop AI coding workflow plugin for Codex, Claude Code, and Cline with structured planning, review, and verification guardrails. - [LLM Transpile](https://github.com/epicsagas/llm-transpile) - Auto-compress .md, .html, and .txt files via PostToolUse hook, cutting context usage by up to 40% with zero workflow change. @@ -237,6 +237,7 @@ Third-party plugins built by the community. [PRs welcome](#contributing)! - [KiCad Happy](https://github.com/aklofas/kicad-happy) - KiCad EDA skills for schematic analysis, PCB layout review, component sourcing, BOM management, and manufacturing preparation. - [Langfuse Observability](https://github.com/avivsinai/langfuse-mcp) - Query traces, debug exceptions, analyze sessions, and manage prompts via MCP tools. - [Launch Fast](https://github.com/BlockchainHB/launchfast_codex_plugin) - Official Launch Fast plugin adapter for rapid SaaS deployment. +- [Maestro: Costguard](https://github.com/mbanderas/costguard) - Cost auditor for Codex that flags CI/cron and cloud-spend waste via read-only provider checks, then previews and applies surgical CI workflow fixes locally without writing to provider accounts or pushing git. - [Mantis](./plugins/deonmenezes/mantishack) - Autonomous bug bounty hunter for authorized engagements — 7-phase FSM (RECON → AUTH → HUNT → CHAIN → VERIFY → GRADE → REPORT), parallel hunter sub-agents, cryptographic scope enforcement, and BLAKE3/Ed25519 Merkle event logs. - [Mobazha](https://github.com/mobazha/mobazha-skills) - Decentralized e-commerce skills — deploy self-hosted stores, import products from Shopify/Amazon, configure custom domains and Telegram bots, set up Tor privacy, and manage your store via MCP. - [MorningAI](https://github.com/octo-patch/MorningAI) - AI news tracking skill that monitors 80+ entities across 6 sources (Reddit, HN, GitHub, Hugging Face, arXiv, X) and generates scored daily reports with infographics and message digests. @@ -249,8 +250,8 @@ Third-party plugins built by the community. [PRs welcome](#contributing)! - [PDF Monster](https://github.com/jbaehova/pdf-monster) - Analyzes PDFs as extracted text, OCR text, rendered page images, and embedded figures for coding agents. - [prompt-to-asset](https://github.com/MohamedAbdallah-14/prompt-to-asset) - Route image-generation prompts to 30+ models (DALL-E, Stable Diffusion, Flux, Midjourney, and more) through a single MCP interface. Install: `npm install -g prompt-to-asset`. - [Remotion Plugin](https://github.com/tim-osterhus/codex-remotion-plugin) - Build parameterized Remotion videos in Codex with the official Remotion docs MCP, composition scaffolding, and a data-driven launch-video workflow. -- [ScrapeGraph AI](https://github.com/ScrapeGraphAI/just-scrape) - AI-powered web scraping CLI to search, scrape, extract structured JSON, crawl, and monitor web pages via the ScrapeGraph AI API. - [Rust Reverse Engineering](https://github.com/jingjing2222/rust-reverse-engineering-skill) - Reverse engineer Rust binaries and libraries: triage targets, demangle symbols, recover crate namespaces, and map panic, unwind, async, and FFI paths. +- [ScrapeGraph AI](https://github.com/ScrapeGraphAI/just-scrape) - AI-powered web scraping CLI to search, scrape, extract structured JSON, crawl, and monitor web pages via the ScrapeGraph AI API. - [sitemd](https://github.com/sitemd-cc/sitemd) - Build websites from Markdown via MCP — 22 tools for creating pages, generating content, validating, running SEO audits, configuring settings, and deploying static sites to Cloudflare Pages. - [Synta MCP](https://github.com/Synta-ai/n8n-mcp-codex-plugin-synta) - Build, edit, validate, and self-heal n8n workflows with Synta MCP tools and Codex-ready workflow guidance. - [Task Scheduler](https://github.com/6Delta9/task-scheduler-codex-plugin) - OpenAI Codex plugin and local MCP server for turning task lists into realistic schedules with blocked dates, capacity overrides, overflow tracking, and markdown planning output. diff --git a/plugins.json b/plugins.json index d2d1f21e..8eb3a089 100644 --- a/plugins.json +++ b/plugins.json @@ -889,6 +889,16 @@ "source": "awesome-codex-plugins", "install_url": "https://raw.githubusercontent.com/BlockchainHB/launchfast_codex_plugin/HEAD/plugins/launchfast/.codex-plugin/plugin.json" }, + { + "name": "Maestro: Costguard", + "url": "https://github.com/mbanderas/costguard", + "owner": "mbanderas", + "repo": "costguard", + "description": "Cost auditor for Codex that flags CI/cron and cloud-spend waste via read-only provider checks, then previews and applies surgical CI workflow fixes locally without writing to provider accounts or pushing git.", + "category": "Tools & Integrations", + "source": "awesome-codex-plugins", + "install_url": "https://raw.githubusercontent.com/mbanderas/costguard/HEAD/.codex-plugin/plugin.json" + }, { "name": "Mobazha", "url": "https://github.com/mobazha/mobazha-skills", diff --git a/plugins/mbanderas/costguard/.codex-plugin/plugin.json b/plugins/mbanderas/costguard/.codex-plugin/plugin.json new file mode 100644 index 00000000..3efa4cdd --- /dev/null +++ b/plugins/mbanderas/costguard/.codex-plugin/plugin.json @@ -0,0 +1,30 @@ +{ + "name": "costguard", + "version": "0.1.0", + "description": "Costguard cost auditor for Codex: read-only cloud + CI spend checks, dry-run-first CI auto-fixes, and a monthly digest, driven by a bundled skill.", + "author": { + "name": "Mark Laursen", + "url": "https://github.com/mbanderas" + }, + "homepage": "https://github.com/mbanderas/costguard#readme", + "repository": "https://github.com/mbanderas/costguard", + "license": "MIT", + "keywords": ["cost-optimization", "ci-minutes", "cron", "cloud-spend", "finops", "audit", "codex"], + "skills": "./skills/", + "interface": { + "displayName": "Costguard", + "shortDescription": "Find and quantify CI/cron and cloud-spend waste", + "composerIcon": "./assets/icon.png", + "longDescription": "Install Costguard in Codex as a plugin: a bundled skill drives the read-only cost auditor — CI/cron waste rules, GitHub/Supabase/Railway/Netlify/Neon billing checks, dry-run-first CI auto-fixes, and a monthly cost digest. Never writes to provider accounts, never pushes git, never prints secrets.", + "developerName": "Mark Laursen", + "category": "Productivity", + "capabilities": ["Interactive", "Write"], + "websiteURL": "https://github.com/mbanderas/costguard", + "brandColor": "#2E9E6B", + "defaultPrompt": [ + "Audit web-app for CI and cron waste.", + "Preview costguard's CI fixes for web-app.", + "Show costguard provider billing checks for all workspaces." + ] + } +} diff --git a/plugins/mbanderas/costguard/.codexignore b/plugins/mbanderas/costguard/.codexignore new file mode 100644 index 00000000..26a5cb36 --- /dev/null +++ b/plugins/mbanderas/costguard/.codexignore @@ -0,0 +1,22 @@ +# Files excluded from the Codex plugin bundle. +# The plugin ships the prebuilt dist/, the costguard skill, the manifest, +# and the icon — development and test sources are not needed at runtime. + +node_modules/ +src/ +tests/ +coverage/ +docs/ + +# Tooling / CI config +.github/ +.githooks/ +.actrc +eslint.config.* +tsconfig*.json +vitest.config.* + +# Misc +*.log +*.tsbuildinfo +.DS_Store diff --git a/plugins/mbanderas/costguard/README.md b/plugins/mbanderas/costguard/README.md new file mode 100644 index 00000000..9a299120 --- /dev/null +++ b/plugins/mbanderas/costguard/README.md @@ -0,0 +1,36 @@ +# Maestro: Costguard + +Cost auditor for Codex that flags CI/cron and cloud-spend waste via read-only +provider checks, then previews and applies surgical CI workflow fixes locally — +without writing to provider accounts or pushing git. + +- **Static half (zero credentials):** reads `.github/workflows/*.yml` and app code + to flag redundant CI triggers, missing `timeout-minutes`, missing concurrency + cancellation, `paths-ignore` gaps, and over-scheduled crons. +- **Billing half (read-only, opt-in):** when a provider token is present, + reconciles live billed resources against a declared allowlist and flags + orphaned / over-provisioned resources across GitHub, Vercel, Supabase, Railway, + Netlify, Neon, Cloudflare, Fly, Render, Sentry, Upstash, MongoDB Atlas, Datadog. +- **Fixes:** `fix` edits only `.github/workflows/*` files, dry-run by default, + applied locally with `--apply`. Never writes to provider accounts, never pushes. + +Part of the **Maestro** collection of agent tooling. + +- Source & docs: https://github.com/mbanderas/costguard +- npm: `@costguard/costguard-mcp` + +## Install (Codex) + +```sh +codex plugin marketplace add mbanderas/costguard +codex plugin add costguard@costguard +``` + +Or run the CLI / MCP server directly with no checkout: + +```sh +npx -y -p @costguard/costguard-mcp costguard audit +npx -y @costguard/costguard-mcp # MCP server +``` + +License: MIT diff --git a/plugins/mbanderas/costguard/assets/icon.png b/plugins/mbanderas/costguard/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..49b130c98973d36690cfaf991136f17b4178ae08 GIT binary patch literal 35620 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 literal 0 HcmV?d00001 diff --git a/plugins/mbanderas/costguard/skills/costguard/SKILL.md b/plugins/mbanderas/costguard/skills/costguard/SKILL.md new file mode 100644 index 00000000..4cae6c1e --- /dev/null +++ b/plugins/mbanderas/costguard/skills/costguard/SKILL.md @@ -0,0 +1,221 @@ +--- +name: costguard +description: Find and quantify CI/cron and cloud-spend waste. Audit repos, run read-only provider billing checks, preview or apply CI auto-fixes, and render a monthly cost digest. +license: MIT +--- + +Drive **Costguard** — a read-only cost auditor for CI minutes, cron schedules, +and cloud provider billing (GitHub Actions, Vercel, Supabase, Railway, Netlify, Neon, Cloudflare, and more). +It finds waste, estimates the monthly dollar cost, and can surgically auto-fix +CI workflow files. It never writes to provider accounts, never pushes git, and +never prints tokens. + +Map the user's request to one Costguard CLI call and run it from the repo root. + +## Command launcher + +Costguard reads a `workspaces.json` registry from the **current working +directory**, so run it from a project that has one (or run `registry init` +first). Pick the launcher that matches your context; below, `costguard +` means whichever you use. + +### If installed via plugin + +When this skill is loaded from the Costguard plugin, run the bundled build — it +ships a prebuilt `dist/cli/index.js`, so no build step is needed. Locate the +plugin root (the dir containing `dist/cli/index.js`): + +- **Claude Code** — it is `${CLAUDE_PLUGIN_ROOT}`: + + ```bash + node "${CLAUDE_PLUGIN_ROOT}/dist/cli/index.js" ... + ``` + +- **Codex** — walk up from this `SKILL.md` to the dir holding + `.codex-plugin/plugin.json`: + + ```bash + node "/dist/cli/index.js" ... + ``` + +### If using npx (no plugin) + +No checkout and no build — run the published CLI directly: + +```bash +npx -y -p @costguard/costguard-mcp costguard ... +``` + +Or, if `costguard` is on `PATH` (`npm i -g @costguard/costguard-mcp`), use it +directly: `costguard ...`. Heads-up: `npx -y @costguard/costguard-mcp` +(no `-p`, no subcommand) starts the MCP **server**, whereas `npx -y -p +@costguard/costguard-mcp costguard ` runs the **CLI**. + +## 1. Audit for waste (the main action) + +```bash +costguard audit # named workspaces +costguard audit --all # every registered workspace +costguard audit --providers all # + read-only cloud billing checks +costguard audit --ci-only # static CI checks only +costguard audit --crons-only # cron checks only +costguard audit --site # + read-only live-site checks (site URL from registry) +costguard audit --substitutions # + cross-tool cheaper-alternative suggestions +costguard audit --json # JSON instead of Markdown +``` + +Prints a report: each finding has a severity, an estimated monthly USD cost, a +detail, and a fix suggestion. Report stdout verbatim. + +## 2. Scan / registry / report + +```bash +costguard scan # discover CI + cron files under the registry root +costguard registry list # show registered workspaces +costguard registry init # create a workspaces.json in the cwd +costguard report # re-render the last saved audit run +``` + +## 3. Auto-fix CI files (dry-run first) + +```bash +costguard fix # dry-run: print a unified-diff preview, write nothing +costguard fix --apply # write the surgical edits to disk (idempotent) +costguard fix --pr # also emit local PR artifacts (no push) +``` + +Default is dry-run. Only deterministic ADD-rule fixers run (timeout, +concurrency, paths-ignore). Costguard never pushes; `--open-pr` is gated and +refuses without an explicit token. + +## 4. Monthly cost digest + +```bash +costguard digest # render the digest from the last run (dry-run) +costguard digest --post # delivery adapter (inert unless configured) +``` + +## 5. Auto-discover providers + +Detect which providers a repo uses — from config files, `package.json` deps, and +env-var **names** (never values, never secrets). Covers all 13 wired providers +plus inngest. + +```bash +costguard discover [dir] # list detected providers + evidence (default dir: .) +costguard discover . --json # JSON: { dir, providers, detections } +costguard discover . --write # union-merge detected providers into ./workspaces.json (non-destructive) +``` + +## 6. Live-site cost checks + +Read-only, GET-only checks on a live URL (no browser, no form submit, no auth +replay). Flags transfer weight, oversized images, missing compression, weak cache +headers, and render-blocking scripts. The `$/mo` headline is the single +`site/transfer-weight` line — sourced when the host bills transfer (Vercel/Netlify), +or an explicit `$0` performance note (Cloudflare Pages static / unknown host). +Per-asset findings (`oversized-image`, `missing-compression`) put their dollar share +in `detail` and carry `estMonthlyUsd: 0` (no double-count); a `$0` performance-only +page never raises a `high` finding, so it never fails CI on cost alone. + +```bash +costguard site # Markdown report +costguard site --json # JSON findings +``` + +`audit --site` runs the same checks for any workspace whose `workspaces.json` +entry has a `site` URL. `audit --substitutions` adds cross-tool +`/cheaper-alternative` suggestions (e.g. a static Vercel/Netlify Pro +site → Cloudflare Pages), each with a sourced saving, migration effort, and +lock-in caveat. + +## Provider billing checks + +`--providers ` adds read-only billing checks for the providers listed +on each workspace in `workspaces.json`. Tokens are read from the environment / +`.env` only. A provider whose token env var is absent is **skipped**, not +failed. Supported: `github`, `supabase`, `railway`, `netlify`, `neon`, `vercel`, +`sentry`, `upstash`, `atlas`, `cloudflare`, `fly`, `render`, `datadog` (+ inngest +detection). + +## 7. MCP tools (for AI coding agents) + +Costguard also ships a bundled **MCP server** that exposes the same engine over a +host-agnostic tool surface (Claude Code, Codex, any MCP host). It wraps the same +read-only engine functions — no new behavior, same posture. In Claude Code it is +declared by `.claude-plugin/.mcp.json` and launched from the bundled build: + +```json +{ "mcpServers": { "costguard": { "command": "node", + "args": ["${CLAUDE_PLUGIN_ROOT}/dist/mcp/server.js"] } } } +``` + +In the plugin, the server runs from the committed `dist/mcp/server.js` — no +install step. + +### Codex MCP config + +For **Codex**, add one of these to `~/.codex/config.toml`. Use npx for a +no-checkout install (pulls the published package), or the bundled build if you +run Codex from the plugin: + +```toml +# npx — no checkout +[mcp_servers.costguard] +command = "npx" +args = ["-y", "@costguard/costguard-mcp"] +``` + +```toml +# bundled plugin build +[mcp_servers.costguard] +command = "node" +args = ["/dist/mcp/server.js"] +``` + +Tools: + +| Tool | Posture | +|---|---| +| `audit_workspace` | read-only; returns a Findings envelope (`includeSite` adds site checks) | +| `discover_providers` | read-only; env-var NAMES only, never values | +| `audit_site` | read-only, GET-only | +| `plan_fix` | dry-run; returns unified diffs only, writes nothing | +| `apply_fix` | writes local CI files; REFUSES unless `confirmApply:true`; never pushes git | +| `plan_live_checks` | plans a live billing read (see below); emits a snippet only with consent | +| `ingest_live_reading` | parses a returned billing figure into a Finding | + +## 8. Live billing checks (`--live`) — opt-in, consent-gated + +`--live` **extends** the read-only posture above: it adds **browser-driven reads +over your already-logged-in session**, performed by the **playwriter** MCP server +under the agent's orchestration. This is a genuine posture change and is treated +as one — **off by default, opt-in, and consent-gated.** costguard's own tools +still never drive a browser and never see credentials: `plan_live_checks` only +emits a **read-only** snippet (navigation + reading rendered billing figures — no +clicks, typing, form submits, credential replay, cookies, localStorage, +sessionStorage, or screenshots), and `ingest_live_reading` only parses the +returned figure. The browser action is performed by playwriter, authorized by you. + +**API-first / browser-fallback:** `plan_live_checks` is API-first when a provider +module exists and its API token resolves from the environment (a deterministic +env-NAME check, no network probe) — in that case prefer `audit_workspace`. Only +when there is no usable API token does it fall back to a browser playbook. + +**Three consent gates (all required):** (1) the host's MCP tool-call consent; +(2) costguard's own per-run confirmation — `plan_live_checks` returns a +`consentNotice` the agent MUST surface, and emits the actionable snippet only when +called with `confirmLive:true`; (3) playwriter's own consent before it executes. + +**Graceful degrade:** if playwriter is not connected, the agent cannot run the +snippet; `ingest_live_reading` returns a `kind:"diagnostic"` Finding (excluded +from cost totals) and the audit never blocks. + +## Notes + +- All provider calls are read-only (GET / read-only GraphQL). No POST/PUT/PATCH/ + DELETE to provider accounts. +- Estimated dollar costs are best-effort and depend on plan/tier; treat them as + directional, not invoices. +- Requires `node` on `PATH`. The bare `costguard` command is optional when the + skill runs from the plugin — use the plugin-root `node` launcher above. From 795af4e8326e5c8b263c2c34128453cc9379610a Mon Sep 17 00:00:00 2001 From: mbanderas Date: Thu, 18 Jun 2026 14:00:02 +0100 Subject: [PATCH 2/2] Set bundle displayName to Maestro: Costguard (matches plugin repo) Co-Authored-By: Claude Opus 4.8 (1M context) --- plugins/mbanderas/costguard/.codex-plugin/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mbanderas/costguard/.codex-plugin/plugin.json b/plugins/mbanderas/costguard/.codex-plugin/plugin.json index 3efa4cdd..4693ce72 100644 --- a/plugins/mbanderas/costguard/.codex-plugin/plugin.json +++ b/plugins/mbanderas/costguard/.codex-plugin/plugin.json @@ -12,7 +12,7 @@ "keywords": ["cost-optimization", "ci-minutes", "cron", "cloud-spend", "finops", "audit", "codex"], "skills": "./skills/", "interface": { - "displayName": "Costguard", + "displayName": "Maestro: Costguard", "shortDescription": "Find and quantify CI/cron and cloud-spend waste", "composerIcon": "./assets/icon.png", "longDescription": "Install Costguard in Codex as a plugin: a bundled skill drives the read-only cost auditor — CI/cron waste rules, GitHub/Supabase/Railway/Netlify/Neon billing checks, dry-run-first CI auto-fixes, and a monthly cost digest. Never writes to provider accounts, never pushes git, never prints secrets.",