diff --git a/.agents/skills/verify/SKILL.md b/.agents/skills/verify/SKILL.md new file mode 100644 index 000000000..c0254e2cd --- /dev/null +++ b/.agents/skills/verify/SKILL.md @@ -0,0 +1,206 @@ +--- +name: verify +description: >- + Orchestrate repo-level verification of a PR by pushing changes, then polling + CI checks, PR review, and QA workflows until all pass — or until issues are + found that need fixing. The agent reads feedback, fixes code, pushes again, + and repeats. Uses only standard `gh` CLI commands that work on any GitHub repo. +triggers: +- /verify +--- + +# /verify — Repo-Level Verification via Polling + +Orchestrate the push → poll → fix → push loop for a pull request. +You poll the repo's verifiers with `gh` CLI, read feedback, fix issues, and iterate. +No scripts — you are the orchestration loop. + +Requires: `gh` CLI authenticated with repo access, a PR branch. + +## Discover what the repo has + +Not every repo has all three verification layers. Before entering the loop, +check which ones exist. Only poll layers that are actually set up. + +```bash +gh workflow list --json name --jq '.[].name' +``` + +- **CI checks** — almost every repo has these. If `gh pr checks` returns results, CI is present. +- **PR review bot** — look for a workflow named like "PR Review" or "pr-review" in the output above, or check for `.github/workflows/pr-review*.yml` in the repo. If it's not there, the repo doesn't have automated PR review. Skip step 3 entirely. +- **QA bot** — look for a workflow named like "QA" or "qa-changes". If it's not there, the repo doesn't have automated QA. Skip step 4 entirely. + +A repo might have only CI. Or CI + review. Or all three. Your "all passed" +condition is: every *present* layer is green. Don't block waiting for layers +that don't exist. + +## The loop + +1. Push and ensure PR exists. +2. Poll each present verification layer. +3. Decide: all passed? fix needed? wait? +4. If fix needed — fix, commit, push, re-request review from bots, go to 2. +5. If waiting — sleep 30-60s, go to 2. +6. If all present layers passed on the *current* SHA — done. + +IMPORTANT: pushing a fix is NOT the end. After every fix+push you MUST +re-request review from the review bot (if present) and go back to step 2. +The loop only ends when the verifiers pass on your latest SHA. Addressing +feedback and pushing a commit is just one iteration — the bot needs to +review the new code too. + +## Step 1 — Push and ensure PR exists + +```bash +git push origin HEAD +gh pr create --fill 2>/dev/null || true +gh pr view --json number,url,headRefOid --jq '"\(.number) \(.url) \(.headRefOid)"' +``` + +## Step 2 — Poll CI checks + +```bash +gh pr checks --json name,state,bucket --jq ' + { passed: [.[] | select(.bucket=="pass")] | length, + failed: [.[] | select(.bucket=="fail")] | length, + pending: [.[] | select(.bucket=="pending")] | length }' +``` + +- Zero failed, zero pending → CI green. +- Any pending → wait and re-poll. +- Any failed → diagnose (see "CI failure classification" below). + +To inspect a failure: + +```bash +SHA=$(gh pr view --json headRefOid --jq .headRefOid) +gh run list --commit "$SHA" --status failure --json databaseId,name,conclusion \ + --jq '.[] | "\(.databaseId)\t\(.name)\t\(.conclusion)"' +gh run view --log-failed +``` + +## Step 3 — Poll PR review (if present) + +Skip this step if the repo has no review bot. + +```bash +gh pr view --json reviews --jq ' + [.reviews[] | select( + .authorAssociation == "OWNER" or + .authorAssociation == "MEMBER" or + .authorAssociation == "COLLABORATOR" or + (.author.login | test("openhands|all-hands-bot"; "i")) + )] | last | { state: .state, reviewer: .author.login, body: .body[0:300] }' +``` + +- `APPROVED` → review passed. +- `CHANGES_REQUESTED` → read the body and inline comments, fix code. +- `COMMENTED` → may have actionable suggestions; read and decide. +- No matching review yet → bot may still be running; wait and re-poll. + +Inline review comments (when changes requested): + +```bash +gh api "repos/{owner}/{repo}/pulls/{number}/comments" \ + --jq '.[] | select(.user.login | test("openhands|all-hands-bot"; "i")) + | { path: .path, line: .line, body: .body[0:200] }' +``` + +## Step 4 — Poll QA report (if present) + +Skip this step if the repo has no QA bot. + +QA reports are PR issue comments with a status line like `Status: PASS`. + +```bash +gh api "repos/{owner}/{repo}/issues/{number}/comments" --paginate \ + --jq '[.[] | select( + (.user.login | test("openhands|all-hands-bot"; "i")) and + (.body | test("Status:\\s*(PASS|FAIL|PARTIAL)"; "i")) + )] | last | { author: .user.login, body: .body[0:500], url: .html_url }' +``` + +- `PASS` → QA passed. +- `FAIL` → read details, fix code. +- `PARTIAL` → some passed, some failed; read details. +- No QA comment yet → bot may still be running; wait and re-poll. + +## Step 5 — Decide and act + +For each present layer, check its status. If a layer is not present in the +repo, treat it as passing. + +- All present layers green on current SHA → done. +- CI failed → fix code, or rerun if flaky (see below). +- Review requested changes → read comments, fix, push. +- QA failed/partial → read report, fix, push. +- Anything still pending → sleep 30-60s, re-poll. +- PR closed/merged → stop. + +After fixing, commit, push, AND re-request review: + +```bash +git add -A +git commit -m "fix: address " +git push origin HEAD + +# Re-request review from the bot so it reviews the new SHA: +gh pr comment --body "Addressed feedback in $(git rev-parse --short HEAD). Ready for another look." +gh api -X POST "repos/{owner}/{repo}/pulls/{number}/requested_reviewers" \ + -f 'reviewers[]=all-hands-bot' +``` + +Then go back to step 2. You are not done until the bot reviews the new +SHA and all present layers pass. + +## CI failure classification + +Branch-related (fix the code): +- Compile/lint/typecheck failures in files you touched +- Deterministic test failures in changed areas +- Snapshot or static-analysis violations from your changes + +Flaky / unrelated (rerun the jobs): +- Network/DNS/registry timeouts +- Runner provisioning or startup failures +- GitHub Actions infrastructure errors +- Non-deterministic failures in code you didn't touch + +Rerun: `gh run rerun --failed` + +Retry budget: at most 3 reruns per SHA. After that, treat as real. + +## Stop conditions + +Stop ONLY when: +- All present verification layers passed on the current SHA. +- PR closed or merged (`gh pr view --json state --jq .state`). +- Retry budget exhausted — CI still failing after 3 reruns of the same SHA. +- Blocked on something requiring user input. + +NOT a stop condition: +- You pushed a fix commit. That's just one iteration — re-request review and keep going. +- You replied to review comments. The bot still needs to review the new code. +- CI is green but review bot hasn't re-reviewed your fix yet. Wait for it. + +Keep going when: +- Checks still pending. +- Bots haven't posted yet (few minutes after push). +- Just pushed a fix and CI hasn't started. + +## Polling cadence + +- CI pending/failing: every 30-60s. +- CI green: back off (60s, 2m, 4m), reset on any state change. +- Just pushed a fix: re-poll immediately. + +## vs babysit-pr + +`/verify` is an active orchestrator — you write code, push, poll, fix, repeat. +`/babysit-pr` is a passive monitor — watches someone else's PR via a Python script. +Use `/verify` when you're the coding agent. Use `/babysit-pr` when you just need to watch. + +## References + +- Verification signal details: `references/workflow-signals.md` +- CI failure heuristics: same as `babysit-pr/references/heuristics.md` diff --git a/.github/scripts/sync_use_case_automations.py b/.github/scripts/sync_use_case_automations.py new file mode 100644 index 000000000..df40cb2b4 --- /dev/null +++ b/.github/scripts/sync_use_case_automations.py @@ -0,0 +1,229 @@ +#!/usr/bin/env python3 +""" +Sync use-case automation cards to the automations overview page. + +Each use-case page under ``openhands/usage/use-cases/`` is the **source of +truth** for its automation content. If a page's YAML frontmatter contains +an ``automation:`` block, this script generates a card for it in the +automations overview page. + +The generated card grid lives between marker comments: + {/* BEGIN:use-case-automations */} … {/* END:use-case-automations */} + +Each card links to the use-case page's ``#automate-this`` section where the +full prompt and instructions live. + +Required frontmatter fields inside ``automation:``: + - ``icon`` — Font Awesome icon name for the card + - ``summary`` — Short description shown on the card + +The page's ``title`` field is used as the card title (no duplication). + +Usage: + python .github/scripts/sync_use_case_automations.py # write mode + python .github/scripts/sync_use_case_automations.py --check # CI check + +Exit codes: + 0 — target page is in sync (or was updated in write mode) + 1 — target page is out of sync (check mode) or validation error +""" + +from __future__ import annotations + +import argparse +import re +import sys +from pathlib import Path + +import yaml + +REPO_ROOT = Path(__file__).resolve().parents[2] +AUTOMATIONS_PAGE = REPO_ROOT / "openhands" / "usage" / "automations" / "overview.mdx" +USE_CASES_DIR = REPO_ROOT / "openhands" / "usage" / "use-cases" + +FRONTMATTER_RE = re.compile(r"\A---\n(.*?)\n---", re.DOTALL) +REQUIRED_FIELDS = ("icon", "summary") + + +# ── Frontmatter parsing ────────────────────────────────────────────── + +def parse_frontmatter(text: str) -> dict: + m = FRONTMATTER_RE.match(text) + if not m: + return {} + return yaml.safe_load(m.group(1)) or {} + + +def collect_use_cases() -> list[tuple[str, str, dict]]: + """Return (slug, page_title, automation_dict) for use-cases with automation metadata.""" + results: list[tuple[str, str, dict]] = [] + errors: list[str] = [] + + for page in sorted(USE_CASES_DIR.glob("*.mdx")): + if page.name == "overview.mdx": + continue + fm = parse_frontmatter(page.read_text()) + if "automation" not in fm: + continue + + auto = fm["automation"] + rel = page.relative_to(REPO_ROOT) + file_has_errors = False + + for field in REQUIRED_FIELDS: + if field not in auto: + errors.append(f" {rel}: missing automation.{field}") + file_has_errors = True + + if "title" not in fm: + errors.append(f" {rel}: missing top-level title") + file_has_errors = True + + if not file_has_errors: + results.append((page.stem, fm["title"], auto)) + + if errors: + print("❌ Frontmatter validation errors:", file=sys.stderr) + for e in errors: + print(e, file=sys.stderr) + sys.exit(1) + + return results + + +# ── Generator ───────────────────────────────────────────────────────── + + +def generate_card_section(use_cases: list[tuple[str, str, dict]]) -> str: + """Generate the ``use-case-automations`` card grid. + + Each card links to the use-case page's #automate-this section. + """ + parts: list[str] = [] + + parts.append( + "Each use case has a ready-to-use automation prompt. " + "Click a card to see the full instructions.\n" + "\n" + "" + ) + + for slug, title, auto in use_cases: + parts.append( + f' \n' + f' {auto["summary"]}\n' + f' ' + ) + + parts.append("") + + return "\n".join(parts) + + +# ── Marker replacement ─────────────────────────────────────────────── + + +def replace_marker_section( + content: str, marker: str, new_body: str, filepath: Path +) -> str: + """Replace everything between BEGIN: and END:.""" + begin_pat = re.compile( + rf"\{{/\*\s*BEGIN:{re.escape(marker)}\s*(?:—[^*]*)?\*/\}}" + ) + end_pat = re.compile( + rf"\{{/\*\s*END:{re.escape(marker)}\s*\*/\}}" + ) + + begin_m = begin_pat.search(content) + end_m = end_pat.search(content) + + if not begin_m and not end_m: + print( + f"❌ {filepath.relative_to(REPO_ROOT)}: " + f"missing both BEGIN:{marker} and END:{marker} markers", + file=sys.stderr, + ) + sys.exit(1) + if not begin_m: + print( + f"❌ {filepath.relative_to(REPO_ROOT)}: " + f"missing BEGIN:{marker} marker", + file=sys.stderr, + ) + sys.exit(1) + if not end_m: + print( + f"❌ {filepath.relative_to(REPO_ROOT)}: " + f"missing END:{marker} marker", + file=sys.stderr, + ) + sys.exit(1) + if begin_m.start() >= end_m.start(): + print( + f"❌ {filepath.relative_to(REPO_ROOT)}: " + f"BEGIN:{marker} must come before END:{marker}", + file=sys.stderr, + ) + sys.exit(1) + + return ( + content[: begin_m.start()] + + begin_m.group(0) + + "\n\n" + + new_body + + "\n\n" + + end_m.group(0) + + content[end_m.end() :] + ) + + +# ── Main ────────────────────────────────────────────────────────────── + + +def main() -> int: + parser = argparse.ArgumentParser( + description="Sync use-case automation cards to the automations page." + ) + parser.add_argument( + "--check", + action="store_true", + help="Check mode: exit 1 if the page is out of sync (for CI).", + ) + args = parser.parse_args() + + use_cases = collect_use_cases() + if not use_cases: + print("No use-case pages with automation frontmatter found.") + return 0 + + original = AUTOMATIONS_PAGE.read_text() + generated = generate_card_section(use_cases) + updated = replace_marker_section( + original, "use-case-automations", generated, AUTOMATIONS_PAGE + ) + + if updated == original: + print("✅ Automations page is in sync.") + return 0 + + if args.check: + print( + f"❌ {AUTOMATIONS_PAGE.relative_to(REPO_ROOT)} is out of sync " + "with use-case frontmatter.\n" + "\n" + "Run: python .github/scripts/sync_use_case_automations.py\n" + "Then commit the updated file." + ) + return 1 + + AUTOMATIONS_PAGE.write_text(updated) + print(f"✅ Updated {AUTOMATIONS_PAGE.relative_to(REPO_ROOT)}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/.github/workflows/sync-use-case-automations.yml b/.github/workflows/sync-use-case-automations.yml new file mode 100644 index 000000000..3cb603ff3 --- /dev/null +++ b/.github/workflows/sync-use-case-automations.yml @@ -0,0 +1,33 @@ +name: Sync Use-Case Automations + +on: + pull_request: + branches: + - '**' + paths: + - 'openhands/usage/automations/overview.mdx' + - 'openhands/usage/use-cases/**' + - '.github/scripts/sync_use_case_automations.py' + - '.github/workflows/sync-use-case-automations.yml' + +permissions: + contents: read + +jobs: + check-sync: + name: Check use-case ↔ automation sync + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install dependencies + run: pip install pyyaml + + - name: Validate sync + run: python .github/scripts/sync_use_case_automations.py --check diff --git a/docs.json b/docs.json index 0dc442dda..62905d8df 100644 --- a/docs.json +++ b/docs.json @@ -416,8 +416,7 @@ "pages": [ "openhands/usage/automations/overview", "openhands/usage/automations/creating-automations", - "openhands/usage/automations/managing-automations", - "openhands/usage/automations/examples" + "openhands/usage/automations/managing-automations" ] } ] @@ -703,6 +702,10 @@ { "source": "/openhands/usage/runtimes/daytona", "destination": "/openhands/usage/v0/runtimes/V0_daytona" + }, + { + "source": "/openhands/usage/automations/examples", + "destination": "/openhands/usage/automations/overview" } ] } diff --git a/openhands/usage/automations/creating-automations.mdx b/openhands/usage/automations/creating-automations.mdx index 99a4b58ca..14dd9c4ee 100644 --- a/openhands/usage/automations/creating-automations.mdx +++ b/openhands/usage/automations/creating-automations.mdx @@ -141,5 +141,5 @@ Once your automation is created: ## Next Steps -- [View example automations](/openhands/usage/automations/examples) +- [Automations overview & examples](/openhands/usage/automations/overview) - [Manage your automations](/openhands/usage/automations/managing-automations) diff --git a/openhands/usage/automations/examples.mdx b/openhands/usage/automations/examples.mdx deleted file mode 100644 index 5a5fec4e9..000000000 --- a/openhands/usage/automations/examples.mdx +++ /dev/null @@ -1,158 +0,0 @@ ---- -title: Automation Examples -description: Practical examples for common automation use cases. ---- - - -**Beta Feature**: Automations is currently in beta and available for **OpenHands Cloud** and **OpenHands Enterprise** users only. - - -Copy and adapt these examples to create your own automations. Just paste the prompt into a conversation with OpenHands. - - -These examples reference services like Slack and GitHub. Git providers you logged in with are automatically available, but other services like Slack require [MCP configuration](/openhands/usage/settings/mcp-settings). - - -## Reporting - -### Daily GitHub Summary - -``` -Create an automation called "Daily GitHub Summary" that runs every weekday at 9 AM Eastern. - -It should: -1. Summarize PRs opened, merged, and reviewed in the last 24 hours -2. List any PRs that have been open for more than 3 days -3. Format as a clean markdown summary -4. Post to the #engineering Slack channel -``` - -### Weekly Metrics Report - -``` -Create an automation called "Weekly Metrics" that runs every Monday at 9 AM. - -It should generate a weekly report covering: -- GitHub activity (commits, PRs merged, issues closed) -- Open issues grouped by priority -- PRs awaiting review for more than 3 days - -Save the report to weekly-reports/ with the current date in the filename. -``` - -## Monitoring - -### API Health Check - -``` -Create an automation called "API Health Monitor" that runs every 30 minutes. - -It should check https://api.example.com/health and: -- If the response is not 200 OK, send an alert to #alerts with the status code and response body -- If healthy, just log success without alerting anyone -``` - -### SSL Certificate Monitor - -``` -Create an automation called "SSL Monitor" that runs daily at 8 AM. - -It should check SSL certificate expiry for these domains: -- api.example.com -- app.example.com -- www.example.com - -If any certificate expires within 30 days, alert #devops with the domain and days remaining. -``` - -## Maintenance - -### Weekly Cleanup - -``` -Create an automation called "Weekly Cleanup" that runs every Sunday at 2 AM UTC. - -It should: -1. Find and delete temporary files older than 7 days -2. Create a summary of what was removed (file paths and sizes) -3. Post the cleanup summary to #ops -``` - -### Backup Verification - -``` -Create an automation called "Backup Check" that runs daily at 6 AM. - -It should verify that database backups exist and were created within the last 24 hours. -List the most recent backup for each database with its timestamp and size. -If any backup is missing or stale, send an urgent alert to #alerts. -``` - -## Data Sync - -### Analytics Data Sync - -``` -Create an automation called "Analytics Sync" that runs every 6 hours. - -It should: -1. Pull the latest data from our analytics API -2. Update metrics.json with the new data -3. Calculate week-over-week changes for key metrics -4. If any metric changed by more than 20%, flag it in a summary message -``` - -## Code Quality - -### Dependency Checker - -``` -Create an automation called "Dependency Checker" that runs every Monday at 8 AM. - -It should: -1. Scan all package.json and requirements.txt files -2. Check for outdated dependencies -3. Create a report listing packages with available updates (grouped by major/minor/patch) -4. Post the report to #engineering -``` - -### Security Scan - -``` -Create an automation called "Security Scan" that runs daily at 3 AM. - -It should run a security audit: -1. Check for known vulnerabilities in dependencies -2. Scan for hardcoded secrets or API keys -3. Look for common security misconfigurations - -Create a detailed report and alert #security if any high or critical issues are found. -``` - -## Tips for Writing Good Prompts - -### Be Specific About Actions - -Tell the automation exactly what to do: -- "Check X and if Y, then Z" -- "Generate a report and save it to..." -- "Fetch data, compare with expected values, and report differences" - -### Include Error Handling - -Specify what should happen when things go wrong: -- "If the response is not 200..." -- "If any backup is missing..." -- "If the check fails, alert the team" - -### Define Where Results Go - -Be explicit about outputs: -- "Post to the #channel Slack channel" -- "Save to reports/ with the current date" -- "Create a GitHub issue with the findings" - -## Next Steps - -- [Creating Automations](/openhands/usage/automations/creating-automations) — More details on writing prompts -- [Managing Automations](/openhands/usage/automations/managing-automations) — Update, disable, or delete automations diff --git a/openhands/usage/automations/managing-automations.mdx b/openhands/usage/automations/managing-automations.mdx index 86575456a..88bb02f00 100644 --- a/openhands/usage/automations/managing-automations.mdx +++ b/openhands/usage/automations/managing-automations.mdx @@ -98,5 +98,5 @@ Deleting an automation is permanent. Consider disabling it instead if you might ## Next Steps -- [View example automations](/openhands/usage/automations/examples) +- [Automations overview & examples](/openhands/usage/automations/overview) - [Create new automations](/openhands/usage/automations/creating-automations) diff --git a/openhands/usage/automations/overview.mdx b/openhands/usage/automations/overview.mdx index 475f604d6..85c8003c0 100644 --- a/openhands/usage/automations/overview.mdx +++ b/openhands/usage/automations/overview.mdx @@ -102,7 +102,170 @@ You can also list existing automations, enable/disable them, or trigger manual r - **Configured LLM** in your [settings](https://app.all-hands.dev/settings) - **Stored secrets** (optional) for any additional API keys your automations need (e.g., Slack tokens) +--- + +## Use Case Automations + +{/* BEGIN:use-case-automations — auto-generated from use-case frontmatter */} + +Each use case has a ready-to-use automation prompt. Click a card to see the full instructions. + + + + Review open PRs daily for bugs, style issues, and security concerns. + + + Check for outdated packages weekly and report available updates. + + + Monitor API health, analyze errors, and alert your team automatically. + + + Scan dependencies for known CVEs, find hardcoded secrets, and alert your team on a schedule. + + + +{/* END:use-case-automations */} + +## General Automations + +Ready-to-use templates for common operational tasks. + + + + Summarize PRs opened, merged, and reviewed daily. + + + Generate weekly GitHub activity and issue reports. + + + Check SSL expiry dates and alert before they lapse. + + + Remove stale temporary files and report what was cleaned. + + + Verify database backups exist and are recent. + + + Pull analytics data periodically and flag big changes. + + + +### Daily GitHub Summary + +``` +Create an automation called "Daily GitHub Summary" that runs every weekday at 9 AM Eastern. + +It should: +1. Summarize PRs opened, merged, and reviewed in the last 24 hours +2. List any PRs that have been open for more than 3 days +3. Format as a clean markdown summary +4. Post to the #engineering Slack channel +``` + +### Weekly Metrics Report + +``` +Create an automation called "Weekly Metrics" that runs every Monday at 9 AM. + +It should generate a weekly report covering: +- GitHub activity (commits, PRs merged, issues closed) +- Open issues grouped by priority +- PRs awaiting review for more than 3 days + +Save the report to weekly-reports/ with the current date in the filename. +``` + +### SSL Certificate Monitor + +``` +Create an automation called "SSL Monitor" that runs daily at 8 AM. + +It should check SSL certificate expiry for these domains: +- api.example.com +- app.example.com +- www.example.com + +If any certificate expires within 30 days, alert #devops with the domain and days remaining. +``` + +### Weekly Cleanup + +``` +Create an automation called "Weekly Cleanup" that runs every Sunday at 2 AM UTC. + +It should: +1. Find and delete temporary files older than 7 days +2. Create a summary of what was removed (file paths and sizes) +3. Post the cleanup summary to #ops +``` + +### Backup Verification + +``` +Create an automation called "Backup Check" that runs daily at 6 AM. + +It should verify that database backups exist and were created within the last 24 hours. +List the most recent backup for each database with its timestamp and size. +If any backup is missing or stale, send an urgent alert to #alerts. +``` + +### Analytics Data Sync + +``` +Create an automation called "Analytics Sync" that runs every 6 hours. + +It should: +1. Pull the latest data from our analytics API +2. Update metrics.json with the new data +3. Calculate week-over-week changes for key metrics +4. If any metric changed by more than 20%, flag it in a summary message +``` + +--- + +## Tips for Writing Good Prompts + + + + Tell the automation exactly what to do: + - "Check X and if Y, then Z" + - "Generate a report and save it to..." + - "Fetch data, compare with expected values, and report differences" + + + Specify what should happen when things go wrong: + - "If the response is not 200..." + - "If any backup is missing..." + - "If the check fails, alert the team" + + + Be explicit about outputs: + - "Post to the #channel Slack channel" + - "Save to reports/ with the current date" + - "Create a GitHub issue with the findings" + + + ## Next Steps -- [Creating Automations](/openhands/usage/automations/creating-automations) — Detailed guide with prompt tips -- [Examples](/openhands/usage/automations/examples) — Common automation patterns +- [Creating Automations](/openhands/usage/automations/creating-automations) — More details on writing prompts +- [Managing Automations](/openhands/usage/automations/managing-automations) — Update, disable, or delete automations +- [Use Cases Overview](/openhands/usage/use-cases/overview) — Explore the full use case guides behind these automations diff --git a/openhands/usage/use-cases/code-review.mdx b/openhands/usage/use-cases/code-review.mdx index 52b1b78af..22e0d1efd 100644 --- a/openhands/usage/use-cases/code-review.mdx +++ b/openhands/usage/use-cases/code-review.mdx @@ -1,6 +1,10 @@ --- title: Automated Code Review description: Set up automated PR reviews using OpenHands and the Software Agent SDK +automation: + icon: code-pull-request + summary: >- + Review open PRs daily for bugs, style issues, and security concerns. --- +## Automate This + +You can schedule daily code reviews using [OpenHands Automations](/openhands/usage/automations/overview). +Copy this prompt into a new conversation to set one up: + +``` +Create an automation called "Daily Code Review" that runs every weekday at 9 AM. + +It should: +1. Find all open PRs that have no reviews yet +2. For each PR, review the diff for bugs, style issues, and security concerns +3. Post a summary of findings as a comment on each PR + +Learn more at https://docs.openhands.dev/openhands/usage/use-cases/code-review +``` + +For inline review comments on every push, use the +[pr-review plugin](https://github.com/OpenHands/extensions/tree/main/plugins/pr-review) +as a GitHub Action instead. + ## Related Resources - [PR Review Workflow Reference](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/02_pr_review) - Full workflow example and agent script diff --git a/openhands/usage/use-cases/dependency-upgrades.mdx b/openhands/usage/use-cases/dependency-upgrades.mdx index 7dad9000b..53b3867f0 100644 --- a/openhands/usage/use-cases/dependency-upgrades.mdx +++ b/openhands/usage/use-cases/dependency-upgrades.mdx @@ -1,6 +1,10 @@ --- title: Dependency Upgrades description: Automating dependency updates and upgrades with OpenHands +automation: + icon: arrow-up-right-dots + summary: >- + Check for outdated packages weekly and report available updates. --- Keeping dependencies up to date is essential for security, performance, and access to new features. OpenHands can help you identify outdated dependencies, plan upgrades, handle breaking changes, and validate that your application still works after updates. @@ -277,6 +281,23 @@ Create an upgrade plan that handles all these together, addressing breaking changes in the correct order. ``` +## Automate This + +You can schedule weekly dependency checks using [OpenHands Automations](/openhands/usage/automations/overview). +Copy this prompt into a new conversation to set one up: + +``` +Create an automation called "Dependency Checker" that runs every Monday at 8 AM. + +It should: +1. Scan all package.json and requirements.txt files +2. Check for outdated dependencies +3. Create a report listing packages with available updates (grouped by major/minor/patch) +4. Post the report to #engineering + +Learn more at https://docs.openhands.dev/openhands/usage/use-cases/dependency-upgrades +``` + ## Related Resources - [Vulnerability Remediation](/openhands/usage/use-cases/vulnerability-remediation) - Fix security vulnerabilities diff --git a/openhands/usage/use-cases/incident-triage.mdx b/openhands/usage/use-cases/incident-triage.mdx index 6f816f1ff..f5156b919 100644 --- a/openhands/usage/use-cases/incident-triage.mdx +++ b/openhands/usage/use-cases/incident-triage.mdx @@ -1,6 +1,10 @@ --- title: Incident Triage description: Using OpenHands to investigate and resolve production incidents +automation: + icon: triangle-exclamation + summary: >- + Monitor API health, analyze errors, and alert your team automatically. --- +## Automate This + +You can set up continuous health monitoring using [OpenHands Automations](/openhands/usage/automations/overview). +Copy this prompt into a new conversation to set one up: + +``` +Create an automation called "API Health Monitor" that runs every 30 minutes. + +It should check https://api.example.com/health and: +- If the response is not 200 OK, send an alert to #alerts with the status code and response body +- If healthy, just log success without alerting anyone + +Learn more at https://docs.openhands.dev/openhands/usage/use-cases/incident-triage +``` + +For deeper error analysis with Datadog integration, see the +[Datadog debugging workflow](https://github.com/OpenHands/software-agent-sdk/tree/main/examples/03_github_workflows/04_datadog_debugging). + ## Related Resources - [OpenHands SDK Repository](https://github.com/OpenHands/software-agent-sdk) - Build custom AI agents diff --git a/openhands/usage/use-cases/overview.mdx b/openhands/usage/use-cases/overview.mdx index cb1d09cca..8229b463f 100644 --- a/openhands/usage/use-cases/overview.mdx +++ b/openhands/usage/use-cases/overview.mdx @@ -5,6 +5,8 @@ description: Explore how OpenHands can help with common software development cha OpenHands supports a wide variety of software development tasks. Here are some of the key use cases where OpenHands can help accelerate your work. +Each use case can be implemented in different ways—as a one-off conversation, a scheduled [automation](/openhands/usage/automations/overview), a [plugin](https://github.com/OpenHands/extensions), or through the [SDK](/sdk/index). Pick the approach that fits your workflow. + + +## Automate Any Use Case + +Many use cases work best as scheduled automations. Browse ready-to-use automation templates on the [Automations Overview](/openhands/usage/automations/overview) page—just copy a prompt and paste it into OpenHands. + + + + Ready-to-use prompts for vulnerability scans, code reviews, monitoring, and more. + + + Explore plugins in the OpenHands extensions repository for extended capabilities. + + + Build custom workflows and integrations using the Software Agent SDK. + + diff --git a/openhands/usage/use-cases/vulnerability-remediation.mdx b/openhands/usage/use-cases/vulnerability-remediation.mdx index f414db4d1..d56322360 100644 --- a/openhands/usage/use-cases/vulnerability-remediation.mdx +++ b/openhands/usage/use-cases/vulnerability-remediation.mdx @@ -1,6 +1,10 @@ --- title: Vulnerability Remediation description: Using OpenHands to identify and fix security vulnerabilities in your codebase +automation: + icon: shield-halved + summary: >- + Scan dependencies for known CVEs, find hardcoded secrets, and alert your team on a schedule. --- " in output + + def test_multiple_cards_preserve_order(self): + cases = [ + ("aaa", "Alpha", {"icon": "a", "summary": "First"}), + ("bbb", "Beta", {"icon": "b", "summary": "Second"}), + ] + output = generate_card_section(cases) + assert output.index("Alpha") < output.index("Beta") + + def test_empty(self): + output = generate_card_section([]) + assert "" in output + assert 'href=' not in output + + +class TestReplaceMarkerSection: + TEMPLATE = ( + "before\n" + "{/* BEGIN:test-marker */}\nold content\n{/* END:test-marker */}\n" + "after" + ) + DUMMY_PATH = REPO_ROOT / "fake-file.mdx" + + def test_replaces_content(self): + result = replace_marker_section(self.TEMPLATE, "test-marker", "new stuff", self.DUMMY_PATH) + assert "new stuff" in result + assert "old content" not in result + assert "before" in result + assert "after" in result + + def test_preserves_markers(self): + result = replace_marker_section(self.TEMPLATE, "test-marker", "X", self.DUMMY_PATH) + assert "BEGIN:test-marker" in result + assert "END:test-marker" in result + + def test_missing_begin_marker(self): + content = "no markers here\n{/* END:test-marker */}" + with pytest.raises(SystemExit): + replace_marker_section(content, "test-marker", "X", self.DUMMY_PATH) + + def test_missing_end_marker(self): + content = "{/* BEGIN:test-marker */}\nstuff" + with pytest.raises(SystemExit): + replace_marker_section(content, "test-marker", "X", self.DUMMY_PATH) + + def test_missing_both_markers(self): + with pytest.raises(SystemExit): + replace_marker_section("nothing here", "test-marker", "X", self.DUMMY_PATH) + + def test_begin_after_end(self): + content = "{/* END:test-marker */}\n{/* BEGIN:test-marker */}" + with pytest.raises(SystemExit): + replace_marker_section(content, "test-marker", "X", self.DUMMY_PATH) + + def test_marker_with_comment(self): + content = ( + "{/* BEGIN:test-marker — auto-generated */}\nold\n" + "{/* END:test-marker */}" + ) + result = replace_marker_section(content, "test-marker", "new", self.DUMMY_PATH) + assert "new" in result + assert "old" not in result