feat: OpenCode server docs, privacy filter, and self-improving agents (t115, t116, t117)#302
Conversation
- Create tools/ai-assistants/opencode-server.md with comprehensive API docs - Cover server setup, SDK usage, session management, async prompts, SSE events - Include aidevops integration patterns: parallel agents, voice dispatch, testing - Add TypeScript SDK examples and direct HTTP API reference - Update subagent-index.toon with new opencode-server entry - Update overview.md to reference server mode documentation - Mark t115 as started in TODO.md Closes #t115
- Create privacy-filter-helper.sh with scan/filter/apply/patterns commands - Detect 30+ privacy patterns (credentials, PII, internal URLs, paths) - Integrate with secretlint for comprehensive credential detection - Support global (~/.aidevops/config/) and project (.aidevops/) patterns - Create tools/security/privacy-filter.md documentation - Update subagent-index.toon with new security folder and script - Mark t117 as complete in TODO.md This filter is mandatory before creating PRs to public repositories. Used by the self-improving agent system (t116) in the PR phase. Closes #t117
- Create self-improve-helper.sh with analyze/refine/test/pr commands - Analyze phase: Query memory for failure patterns, identify gaps - Refine phase: Generate improvements via OpenCode session - Test phase: Validate proposals in isolated OpenCode sessions - PR phase: Create privacy-filtered PRs with evidence - Create aidevops/self-improving-agents.md documentation - Update subagent-index.toon with new script and docs - Mark t116 and all subtasks as complete in TODO.md The self-improvement cycle enables aidevops to learn from failures, generate improvements, test them in isolation, and contribute back with privacy-safe PRs. Closes #t116
WalkthroughIntroduces a comprehensive self-improving agent system with four-phase workflow (analyze, refine, test, PR), privacy-filtering helper for credential redaction, OpenCode server documentation, and supporting utilities. Includes new scripts, documentation, and configuration updates enabling autonomous code improvement with privacy safeguards. Changes
Sequence DiagramsequenceDiagram
participant Agent as Self-Improving Agent
participant Mem as Memory System
participant OC as OpenCode Server
participant PF as Privacy Filter
participant GH as GitHub/PR
Agent->>Mem: ANALYZE: Query failure patterns<br/>& missing solutions
Mem-->>Agent: Return analysis.json
Agent->>OC: REFINE: Create session<br/>+ send proposals prompt
OC-->>Agent: Generate proposals.json
OC->>Agent: Close session
Agent->>OC: TEST: Create session<br/>+ validate proposals
OC-->>Agent: Return test-results.json
OC->>Agent: Close session
Agent->>PF: PR: Scan for sensitive data<br/>in evidence/code
PF-->>Agent: Preview redactions
Agent->>PF: Apply privacy filter
PF-->>Agent: Redacted content
Agent->>GH: Create privacy-filtered PR<br/>with attestation
GH-->>Agent: PR created (privacy-safe)
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly Related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
Summary of ChangesHello @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 AI DevOps framework by introducing a self-improving agent system, ensuring privacy-safe contributions to public repositories, and providing detailed documentation for programmatic interaction with the OpenCode server. These additions aim to automate the continuous improvement cycle of agents, safeguard sensitive information during public contributions, and facilitate advanced AI orchestration and testing scenarios. Highlights
Changelog
Activity
Using Gemini Code AssistThe 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
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 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
|
|
🔍 Code Quality Report�[0;35m[MONITOR]�[0m Code Review Monitoring Report �[0;34m[INFO]�[0m Latest Quality Status: �[0;34m[INFO]�[0m Recent monitoring activity: 📈 Current Quality Metrics
Generated on: Wed Feb 4 02:20:11 UTC 2026 Generated by AI DevOps Framework Code Review Monitoring |
There was a problem hiding this comment.
Code Review
This pull request introduces impressive new capabilities with the self-improving agent system and a privacy filter, accompanied by comprehensive documentation. The shell scripts are well-structured and follow good practices. However, I've identified a critical issue in the privacy filter's pattern definitions that would cause it to fail silently for several important patterns. I've also noted a few other medium to high severity issues, including a discrepancy between documentation and implementation in the privacy filter, and fragile parsing logic in the self-improvement script. Addressing these points will significantly improve the robustness and reliability of these new features.
| # Exclude test fixtures | ||
| !test/fixtures/ |
There was a problem hiding this comment.
The documentation suggests that paths can be excluded from scans by prefixing them with ! in .aidevops/privacy-patterns.txt. However, the privacy-filter-helper.sh script does not implement this exclusion logic; the load_custom_patterns function reads all non-comment lines as patterns to be detected. This discrepancy is misleading and could cause confusion when users try to handle false positives.
| else | ||
| mapfile -t files < <(find "$target" -type f -not -path '*/\.*' -not -path '*/node_modules/*' 2>/dev/null) | ||
| fi |
There was a problem hiding this comment.
The comment on line 232 states that the file search respects .gitignore. While ripgrep (rg) does this, the fallback find command does not. It uses some -not -path arguments, but this is not as reliable as respecting .gitignore properly. This can lead to scanning files that should be ignored (e.g., build artifacts, logs), causing false positives and slower scans. Consider using git ls-files --cached --others --exclude-standard as a more reliable fallback for git repositories.
|
|
||
| # Extract proposals from response | ||
| local proposals | ||
| proposals=$(echo "$response" | jq -r '.parts[] | select(.type == "text") | .text' 2>/dev/null | grep -o '\[.*\]' | head -1 || echo "[]") |
There was a problem hiding this comment.
The method used to extract JSON proposals from the AI's response is fragile. It uses grep -o '\[.*\]' | head -1, which assumes the entire JSON array is on a single line and is not enclosed in a markdown code block (e.g., json ... ). If the LLM formats the JSON with newlines or wraps it in a code block, this parsing will likely fail or produce an incomplete result. A more robust parsing method that handles multi-line JSON and markdown code blocks should be used to improve reliability.
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Fix all issues with AI agents
In @.agent/aidevops/self-improving-agents.md:
- Around line 33-385: This doc embeds large step-by-step workflows and sample
outputs that should be replaced with high-level pointers to the authoritative
implementations; remove the long inline bash examples, outputs and
troubleshooting blocks and instead summarize the phase (Analyze, Refine, Test,
PR) and link to the actual scripts and artifacts (self-improve-helper.sh,
privacy-filter-helper.sh, memory-helper.sh, opencode serve, and workspace files
like analysis.json/proposals.json/test-results.json) and add file:line
references in the summary to the authoritative implementations so readers follow
the real code for details; keep only minimal examples that are authoritative and
move all commands, sample outputs and troubleshooting into the referenced
scripts/docs.
In @.agent/scripts/privacy-filter-helper.sh:
- Around line 175-206: run_secretlint currently treats any non-zero result from
the npx branch as "secretlint not available" and returns success; change the npx
fallback to first verify npx exists (e.g., command -v npx) and if absent
print_warning and return 0, but if npx is present run npx --yes secretlint
"$target" and treat a non-zero exit as a real failure (print_error "Secretlint:
Potential secrets found!" and return 1) instead of masking it as skipped; update
the npx branch in run_secretlint to explicitly distinguish "npx missing" vs
"scan failed" behaviors.
- Around line 326-399: apply_redactions currently uses sed per-pattern (breaking
on / delimiters and \b, and recreates backups per pattern); change it to use
ripgrep's replace to perform safe, delimiter-free replacements and create a
single backup per file: in apply_redactions (and the matches loop) detect if
command -v rg; for each file create its "${file}.privacy-backup" only once
(before any replacements) and then for replacement run a pipeline applying all
patterns via rg --passthru --replace (iteratively feed the file through rg
--passthru --replace -e "$pattern" --replace '[REDACTED]' into a temp file, or
construct a single stream of replacements) and atomically move the temp into
place; if rg is not available, fallback to perl -pe using s{pattern}[REDACTED}g
with proper escaping so / and \b work; ensure patterns from get_all_patterns are
quoted/handled safely and remove the per-pattern cp "$file"
"${file}.privacy-backup" so backup is only created once per file.
In @.agent/scripts/self-improve-helper.sh:
- Around line 39-46: The CYAN color constant (readonly CYAN='\033[0;36m') is
defined but unused; remove that line from the color definitions in
.agent/scripts/self-improve-helper.sh (the block containing GREEN, BLUE, YELLOW,
RED, PURPLE, CYAN, NC) so static analysis no longer flags an unused variable, or
alternatively use CYAN in any output helper function (e.g., the script's
logging/echo calls) if you prefer to keep it.
- Around line 281-334: The proposals extraction fails for multi-line JSON
because proposals=$(echo "$response" | jq -r '.parts[] | select(.type == "text")
| .text' 2>/dev/null | grep -o '\[.*\]' | head -1 || echo "[]") uses a
single-line grep and a greedy regex; change the extraction to parse the full
response with jq and validate with jq --exit-status to ensure JSON-only output:
call send_prompt as before, capture response, then use jq to locate and parse
the JSON array (e.g., filter .parts[][].text or assemble candidate strings) and
run jq . to validate; if validation fails, log the raw response and return
error; update the variable proposals and the error branch that checks proposals
(the log_warn block) to handle empty/invalid JSON returned by jq and to avoid
silent failures from grep.
In @.agent/tools/ai-assistants/opencode-server.md:
- Around line 90-473: The "TypeScript SDK" and subsequent long example sections
(e.g., headings "Creating a Client", "Session Management", "Sending Prompts",
"Direct HTTP API", and all numbered use-case examples) are too large for this
agent doc; replace the embedded TS/Bash/YAML blocks with short overview text and
explicit pointers to the authoritative examples and implementation (e.g., link
or repo reference to the SDK README and the server/example scripts), and move
the full code samples out to those canonical files; keep only a one-line minimal
snippet or CLI example where necessary and add "See: [authoritative doc or
file:line]" references for "createOpencode/createOpencodeClient", session
methods (session.create, session.prompt/promptAsync), event.subscribe, and the
CI YAML so readers are directed to the real source.
In @.agent/tools/security/privacy-filter.md:
- Around line 44-221: Collapse the long CLI walkthrough in
.agent/tools/security/privacy-filter.md (section starting at the Usage header
with many command examples) into a concise overview that points readers to the
actual implementation script .agent/scripts/privacy-filter-helper.sh with
file:line references for the relevant functions/flags (e.g., the scan, filter,
apply, patterns, and patterns add-project handlers inside
privacy-filter-helper.sh); remove the inline multi-line command blocks and
retain only one brief example for authoritative usage, plus explicit file:line
pointers to the helper script where the full commands and behavior live, and
ensure the "Integration with Self-Improving Agents" and "Git Hooks" sections
reference the specific functions/lines in privacy-filter-helper.sh instead of
embedding full scripts.
- Around line 229-235: The documentation shows a negation pattern
(!test/fixtures/) that privacy-filter-helper.sh does not support; update
.aidevops/privacy-patterns.txt examples and the privacy-filter.md instructions
to remove the negation example and instead show a supported workaround (e.g.,
narrow the regex or move fixtures to ignored paths like .gitignore) and add an
explicit note that privacy-filter-helper.sh treats every line as a positive
regex and does not support leading "!" negation; reference the helper script
name privacy-filter-helper.sh and the patterns file
.aidevops/privacy-patterns.txt so reviewers can locate and edit the offending
example.
🧹 Nitpick comments (4)
TODO.md (1)
232-244: Align t115 status with completed work and sync TOON blocks.t115 is still unchecked even though the PR objectives say it’s implemented. Please mark it completed (with a completed date) and ensure the TOON backlog entries for t115–t117 are updated to match the human-readable status.
🧾 Suggested update
- - [ ] t115 OpenCode server subagent documentation `#docs` `#tools` `#ai-assistants` ~2h (ai:1.5h test:20m read:10m) logged:2026-02-04 started:2026-02-04T12:00Z + - [x] t115 OpenCode server subagent documentation `#docs` `#tools` `#ai-assistants` ~2h actual:?? (ai:1.5h test:20m read:10m) logged:2026-02-04 started:2026-02-04T12:00Z completed:2026-02-04.agent/aidevops/self-improving-agents.md (1)
147-390: Add architecture + self‑assessment protocol pointers to prerequisites/guardrails.
This doc should point readers to.agent/aidevops/architecture.mdand the self‑assessment protocol (complete task first, cite evidence, check duplicates viarg "pattern" .agent/, propose fixes for observable failures) in the prerequisites or safety guardrails.Based on learnings: Before extending aidevops framework, read
.agent/aidevops/architecture.mdto understand agent design patterns (progressive disclosure, context offloading, Ralph loop), extension guidelines, and framework conventions; Apply self-assessment protocol when developing agents: complete task first, cite evidence, check for duplicates usingrg "pattern" .agent/before adding instructions, and propose fixes when observable failures or contradictions are detected..agent/scripts/self-improve-helper.sh (2)
61-99: Add curl timeouts/--fail to avoid hangs in OpenCode calls.
Without timeouts, a stalled server can block the whole loop. Use--connect-timeout/--max-timeand--failfor fast, reliable error handling.As per coding guidelines: .agent/scripts/*.sh: Automation scripts - focus on: Reliability and robustness; Proper exit codes; Error recovery mechanisms.🔧 Proposed fix
- if curl -s "${OPENCODE_URL}/global/health" > /dev/null 2>&1; then + if curl -fsS --connect-timeout 2 --max-time 5 "${OPENCODE_URL}/global/health" > /dev/null 2>&1; then return 0 else return 1 fi @@ - response=$(curl -s -X POST "${OPENCODE_URL}/session" \ + response=$(curl -fsS --connect-timeout 2 --max-time 30 -X POST "${OPENCODE_URL}/session" \ -H "Content-Type: application/json" \ -d "{\"title\": \"$title\"}") @@ - response=$(curl -s -X POST "${OPENCODE_URL}/session/${session_id}/message" \ + response=$(curl -fsS --connect-timeout 2 --max-time 60 -X POST "${OPENCODE_URL}/session/${session_id}/message" \ -H "Content-Type: application/json" \ -d "{\"parts\": [{\"type\": \"text\", \"text\": $(echo "$prompt" | jq -Rs .)}]}") @@ - curl -s -X DELETE "${OPENCODE_URL}/session/${session_id}" > /dev/null + curl -fsS --connect-timeout 2 --max-time 10 -X DELETE "${OPENCODE_URL}/session/${session_id}" > /dev/null
286-307: Embed the self‑assessment protocol in the refine prompt.
Add a short protocol reminder (complete task first, cite evidence, check duplicates viarg "pattern" .agent/, propose fixes when failures/contradictions are observed) so generated proposals comply.Based on learnings: Apply self-assessment protocol when developing agents: complete task first, cite evidence, check for duplicates using
rg "pattern" .agent/before adding instructions, and propose fixes when observable failures or contradictions are detected.
| ```text | ||
| ┌─────────────────────────────────────────────────────────────┐ | ||
| │ Self-Improvement Cycle │ | ||
| ├─────────────────────────────────────────────────────────────┤ | ||
| │ │ | ||
| │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ │ | ||
| │ │ ANALYZE │───▶│ REFINE │───▶│ TEST │───▶│ PR │ │ | ||
| │ └──────────┘ └──────────┘ └──────────┘ └────────┘ │ | ||
| │ │ │ │ │ │ | ||
| │ ▼ ▼ ▼ ▼ │ | ||
| │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ │ | ||
| │ │ Memory │ │ OpenCode │ │ OpenCode │ │ GitHub │ │ | ||
| │ │ Patterns │ │ Session │ │ Session │ │ PR │ │ | ||
| │ └──────────┘ └──────────┘ └──────────┘ └────────┘ │ | ||
| │ │ | ||
| └─────────────────────────────────────────────────────────────┘ | ||
| ``` | ||
|
|
||
| ## Phases | ||
|
|
||
| ### 1. Analyze Phase | ||
|
|
||
| Query memory for failure patterns and identify improvement opportunities. | ||
|
|
||
| ```bash | ||
| self-improve-helper.sh analyze | ||
| ``` | ||
|
|
||
| **What it does:** | ||
| - Queries memory for FAILED_APPROACH entries | ||
| - Queries memory for ERROR_FIX entries | ||
| - Identifies gaps (failures without corresponding solutions) | ||
| - Saves analysis to `analysis.json` | ||
|
|
||
| **Output:** | ||
|
|
||
| ```text | ||
| Memory Summary: | ||
| - Failed approaches: 15 | ||
| - Error fixes: 8 | ||
| - Working solutions: 42 | ||
| - Codebase patterns: 12 | ||
|
|
||
| Gaps identified: 7 (failures without solutions) | ||
| ``` | ||
|
|
||
| ### 2. Refine Phase | ||
|
|
||
| Generate specific improvement proposals using OpenCode. | ||
|
|
||
| ```bash | ||
| self-improve-helper.sh refine [--dry-run] | ||
| ``` | ||
|
|
||
| **What it does:** | ||
| - Creates OpenCode session for improvement generation | ||
| - Sends analysis data with structured prompt | ||
| - Receives proposals as JSON array | ||
| - Saves proposals to `proposals.json` | ||
|
|
||
| **Proposal format:** | ||
|
|
||
| ```json | ||
| { | ||
| "file": ".agent/workflows/git-workflow.md", | ||
| "change_type": "edit", | ||
| "description": "Add guidance for handling merge conflicts", | ||
| "diff": "...", | ||
| "impact": "Reduces merge conflict failures by 30%", | ||
| "test_prompt": "Simulate a merge conflict scenario..." | ||
| } | ||
| ``` | ||
|
|
||
| ### 3. Test Phase | ||
|
|
||
| Validate improvements in isolated OpenCode sessions. | ||
|
|
||
| ```bash | ||
| self-improve-helper.sh test [session-id] | ||
| ``` | ||
|
|
||
| **What it does:** | ||
| - Loads proposals from previous phase | ||
| - Runs each proposal's test_prompt in OpenCode | ||
| - Checks responses for error indicators | ||
| - Saves results to `test-results.json` | ||
|
|
||
| **Test criteria:** | ||
| - Response doesn't contain error keywords | ||
| - Task completes without exceptions | ||
| - Output matches expected patterns | ||
|
|
||
| ### 4. PR Phase | ||
|
|
||
| Create privacy-filtered PR with evidence. | ||
|
|
||
| ```bash | ||
| self-improve-helper.sh pr [--dry-run] | ||
| ``` | ||
|
|
||
| **What it does:** | ||
| - Runs mandatory privacy filter scan | ||
| - Builds PR body with evidence: | ||
| - Memory analysis summary | ||
| - Test results attestation | ||
| - Privacy filter confirmation | ||
| - Creates PR via gh CLI | ||
|
|
||
| **PR includes:** | ||
| - Summary of improvements | ||
| - Evidence from memory analysis | ||
| - Test results for each change | ||
| - Privacy attestation | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| ### OpenCode Server | ||
|
|
||
| Start the server before running improvement cycles: | ||
|
|
||
| ```bash | ||
| opencode serve --port 4096 | ||
| ``` | ||
|
|
||
| Or with authentication: | ||
|
|
||
| ```bash | ||
| OPENCODE_SERVER_PASSWORD=secret opencode serve --port 4096 | ||
| ``` | ||
|
|
||
| ### Memory System | ||
|
|
||
| The analyze phase requires populated memory: | ||
|
|
||
| ```bash | ||
| # Check memory stats | ||
| memory-helper.sh stats | ||
|
|
||
| # Ensure there are failure entries | ||
| memory-helper.sh recall --type FAILED_APPROACH --limit 5 | ||
| ``` | ||
|
|
||
| ### Privacy Filter | ||
|
|
||
| The PR phase requires the privacy filter: | ||
|
|
||
| ```bash | ||
| # Verify installation | ||
| privacy-filter-helper.sh status | ||
|
|
||
| # Test scan | ||
| privacy-filter-helper.sh scan . | ||
| ``` | ||
|
|
||
| ## Configuration | ||
|
|
||
| ### Environment Variables | ||
|
|
||
| | Variable | Default | Description | | ||
| |----------|---------|-------------| | ||
| | `OPENCODE_HOST` | `localhost` | OpenCode server hostname | | ||
| | `OPENCODE_PORT` | `4096` | OpenCode server port | | ||
|
|
||
| ### Workspace Files | ||
|
|
||
| ```text | ||
| ~/.aidevops/.agent-workspace/self-improve/ | ||
| ├── analysis.json # Memory analysis results | ||
| ├── proposals.json # Generated improvement proposals | ||
| └── test-results.json # Test validation results | ||
| ``` | ||
|
|
||
| ## Usage Examples | ||
|
|
||
| ### Full Improvement Cycle | ||
|
|
||
| ```bash | ||
| # 1. Start OpenCode server | ||
| opencode serve --port 4096 & | ||
|
|
||
| # 2. Run improvement cycle | ||
| self-improve-helper.sh analyze | ||
| self-improve-helper.sh refine | ||
| self-improve-helper.sh test | ||
| self-improve-helper.sh pr | ||
|
|
||
| # 3. Review and merge PR | ||
| gh pr view | ||
| ``` | ||
|
|
||
| ### Dry Run Preview | ||
|
|
||
| ```bash | ||
| # Preview what would be generated | ||
| self-improve-helper.sh refine --dry-run | ||
|
|
||
| # Preview PR without creating | ||
| self-improve-helper.sh pr --dry-run | ||
| ``` | ||
|
|
||
| ### Check Status | ||
|
|
||
| ```bash | ||
| self-improve-helper.sh status | ||
| ``` | ||
|
|
||
| Output: | ||
|
|
||
| ```text | ||
| Self-Improvement Status | ||
|
|
||
| ✅ Analysis: 2026-02-04T12:00:00Z (7 gaps) | ||
| ✅ Proposals: 2026-02-04T12:15:00Z (5 proposals) | ||
| ✅ Tests: 2026-02-04T12:30:00Z (5 passed, 0 failed) | ||
| ✅ OpenCode server: Running at http://localhost:4096 | ||
| ``` | ||
|
|
||
| ## Safety Guardrails | ||
|
|
||
| ### Privacy Filter (Mandatory) | ||
|
|
||
| The PR phase will not proceed without passing the privacy filter: | ||
|
|
||
| - Secretlint scan for credentials | ||
| - Pattern-based detection for PII | ||
| - Project-specific patterns from `.aidevops/privacy-patterns.txt` | ||
|
|
||
| ### Worktree Isolation | ||
|
|
||
| All changes must be made in a worktree, not on main: | ||
|
|
||
| ```bash | ||
| # Create worktree for improvements | ||
| wt switch -c feature/self-improve-$(date +%Y%m%d) | ||
|
|
||
| # Run improvement cycle | ||
| self-improve-helper.sh analyze | ||
| # ... | ||
| ``` | ||
|
|
||
| ### Human Approval | ||
|
|
||
| The PR phase requires: | ||
| 1. All tests to pass | ||
| 2. Privacy filter to pass | ||
| 3. Human review before merge | ||
|
|
||
| ### Dry Run Mode | ||
|
|
||
| Always preview with `--dry-run` first: | ||
|
|
||
| ```bash | ||
| self-improve-helper.sh refine --dry-run | ||
| self-improve-helper.sh pr --dry-run | ||
| ``` | ||
|
|
||
| ## Integration with Memory | ||
|
|
||
| ### Storing Learnings | ||
|
|
||
| After successful improvements, store the pattern: | ||
|
|
||
| ```bash | ||
| memory-helper.sh store \ | ||
| --content "Self-improvement: Added merge conflict guidance to git-workflow.md" \ | ||
| --type WORKING_SOLUTION \ | ||
| --tags "self-improve,git,merge-conflict" | ||
| ``` | ||
|
|
||
| ### Querying Patterns | ||
|
|
||
| The analyze phase queries these memory types: | ||
|
|
||
| | Type | Purpose | | ||
| |------|---------| | ||
| | `FAILED_APPROACH` | What didn't work | | ||
| | `ERROR_FIX` | Errors and their fixes | | ||
| | `WORKING_SOLUTION` | Successful approaches | | ||
| | `CODEBASE_PATTERN` | Code conventions | | ||
|
|
||
| ## Scheduling | ||
|
|
||
| ### Manual Trigger | ||
|
|
||
| Run the improvement cycle manually when needed: | ||
|
|
||
| ```bash | ||
| self-improve-helper.sh analyze && \ | ||
| self-improve-helper.sh refine && \ | ||
| self-improve-helper.sh test && \ | ||
| self-improve-helper.sh pr --dry-run | ||
| ``` | ||
|
|
||
| ### Cron Integration (Future) | ||
|
|
||
| The cron agent (t110) will enable scheduled improvement cycles: | ||
|
|
||
| ```bash | ||
| # Weekly improvement analysis (future) | ||
| cron-agent add "self-improve-weekly" \ | ||
| --schedule "0 2 * * 0" \ | ||
| --command "self-improve-helper.sh analyze" | ||
| ``` | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### OpenCode Server Not Running | ||
|
|
||
| ```bash | ||
| # Check if running | ||
| curl http://localhost:4096/global/health | ||
|
|
||
| # Start server | ||
| opencode serve --port 4096 | ||
| ``` | ||
|
|
||
| ### No Memory Entries | ||
|
|
||
| ```bash | ||
| # Check memory stats | ||
| memory-helper.sh stats | ||
|
|
||
| # Store some test entries | ||
| memory-helper.sh store \ | ||
| --content "Test failure: X didn't work because Y" \ | ||
| --type FAILED_APPROACH | ||
| ``` | ||
|
|
||
| ### Privacy Filter Fails | ||
|
|
||
| ```bash | ||
| # See what's detected | ||
| privacy-filter-helper.sh scan . | ||
|
|
||
| # Add exceptions if needed | ||
| privacy-filter-helper.sh patterns add-project 'test\.example\.com' | ||
| ``` | ||
|
|
||
| ### Tests Fail | ||
|
|
||
| Review the test results: | ||
|
|
||
| ```bash | ||
| cat ~/.aidevops/.agent-workspace/self-improve/test-results.json | jq '.' | ||
| ``` | ||
|
|
||
| Refine proposals and re-test: | ||
|
|
||
| ```bash | ||
| self-improve-helper.sh refine | ||
| self-improve-helper.sh test | ||
| ``` | ||
|
|
There was a problem hiding this comment.
Replace large inline workflows with pointers to authoritative sources.
Lines 33‑385 embed step‑by‑step commands, sample outputs, and troubleshooting. For .agent docs, keep this as a high‑level overview and link to authoritative implementations (e.g., .agent/scripts/self-improve-helper.sh with file:line references) so details don’t drift.
As per coding guidelines: .agent/**/*.md: Apply progressive disclosure pattern by using pointers to subagents rather than including inline content in agent documentation; Include code examples only when authoritative; use file:line references to point to actual implementation instead of inline code snippets.
🤖 Prompt for AI Agents
In @.agent/aidevops/self-improving-agents.md around lines 33 - 385, This doc
embeds large step-by-step workflows and sample outputs that should be replaced
with high-level pointers to the authoritative implementations; remove the long
inline bash examples, outputs and troubleshooting blocks and instead summarize
the phase (Analyze, Refine, Test, PR) and link to the actual scripts and
artifacts (self-improve-helper.sh, privacy-filter-helper.sh, memory-helper.sh,
opencode serve, and workspace files like
analysis.json/proposals.json/test-results.json) and add file:line references in
the summary to the authoritative implementations so readers follow the real code
for details; keep only minimal examples that are authoritative and move all
commands, sample outputs and troubleshooting into the referenced scripts/docs.
| # Run secretlint scan first | ||
| run_secretlint() { | ||
| local target="${1:-.}" | ||
|
|
||
| print_header "Running Secretlint scan..." | ||
|
|
||
| if command -v secretlint &> /dev/null; then | ||
| if secretlint "$target" 2>/dev/null; then | ||
| print_success "Secretlint: No secrets detected" | ||
| return 0 | ||
| else | ||
| print_error "Secretlint: Potential secrets found!" | ||
| return 1 | ||
| fi | ||
| elif [[ -f "node_modules/.bin/secretlint" ]]; then | ||
| if ./node_modules/.bin/secretlint "$target" 2>/dev/null; then | ||
| print_success "Secretlint: No secrets detected" | ||
| return 0 | ||
| else | ||
| print_error "Secretlint: Potential secrets found!" | ||
| return 1 | ||
| fi | ||
| else | ||
| # Try npx | ||
| if npx --yes secretlint "$target" 2>/dev/null; then | ||
| print_success "Secretlint: No secrets detected" | ||
| return 0 | ||
| else | ||
| print_warning "Secretlint not available, skipping credential scan" | ||
| return 0 | ||
| fi | ||
| fi |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, confirm the file exists and examine the run_secretlint function
cat -n .agent/scripts/privacy-filter-helper.sh | sed -n '175,206p'Repository: marcusquinn/aidevops
Length of output: 1317
🏁 Script executed:
# Also check if there are any tests or callers of this function
rg "run_secretlint" .agent/scripts/ -A 2 -B 2Repository: marcusquinn/aidevops
Length of output: 660
🏁 Script executed:
# Check the overall structure of the file
wc -l .agent/scripts/privacy-filter-helper.shRepository: marcusquinn/aidevops
Length of output: 107
npx secretlint fallback fails open on findings.
In the npx fallback branch (lines 198-205), any non-zero exit—whether from missing npx, failed execution, or detected secrets—is treated as "not available" and returns success. This masks secrets that secretlint detects. Since the caller checks return codes to track findings, this silent pass introduces security risk.
Add an explicit check for npx availability before attempting the scan, then return error status if the scan fails:
🔧 Proposed fix
- else
- # Try npx
- if npx --yes secretlint "$target" 2>/dev/null; then
- print_success "Secretlint: No secrets detected"
- return 0
- else
- print_warning "Secretlint not available, skipping credential scan"
- return 0
- fi
- fi
+ elif command -v npx &> /dev/null; then
+ if npx --yes secretlint "$target" 2>/dev/null; then
+ print_success "Secretlint: No secrets detected"
+ return 0
+ else
+ print_error "Secretlint: Potential secrets found or scan failed"
+ return 1
+ fi
+ else
+ print_warning "Secretlint not available, skipping credential scan"
+ return 0
+ fiPer .agent/scripts/*.sh guidelines: maintain reliability, robust exit codes, and proper error recovery.
📝 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.
| # Run secretlint scan first | |
| run_secretlint() { | |
| local target="${1:-.}" | |
| print_header "Running Secretlint scan..." | |
| if command -v secretlint &> /dev/null; then | |
| if secretlint "$target" 2>/dev/null; then | |
| print_success "Secretlint: No secrets detected" | |
| return 0 | |
| else | |
| print_error "Secretlint: Potential secrets found!" | |
| return 1 | |
| fi | |
| elif [[ -f "node_modules/.bin/secretlint" ]]; then | |
| if ./node_modules/.bin/secretlint "$target" 2>/dev/null; then | |
| print_success "Secretlint: No secrets detected" | |
| return 0 | |
| else | |
| print_error "Secretlint: Potential secrets found!" | |
| return 1 | |
| fi | |
| else | |
| # Try npx | |
| if npx --yes secretlint "$target" 2>/dev/null; then | |
| print_success "Secretlint: No secrets detected" | |
| return 0 | |
| else | |
| print_warning "Secretlint not available, skipping credential scan" | |
| return 0 | |
| fi | |
| fi | |
| # Run secretlint scan first | |
| run_secretlint() { | |
| local target="${1:-.}" | |
| print_header "Running Secretlint scan..." | |
| if command -v secretlint &> /dev/null; then | |
| if secretlint "$target" 2>/dev/null; then | |
| print_success "Secretlint: No secrets detected" | |
| return 0 | |
| else | |
| print_error "Secretlint: Potential secrets found!" | |
| return 1 | |
| fi | |
| elif [[ -f "node_modules/.bin/secretlint" ]]; then | |
| if ./node_modules/.bin/secretlint "$target" 2>/dev/null; then | |
| print_success "Secretlint: No secrets detected" | |
| return 0 | |
| else | |
| print_error "Secretlint: Potential secrets found!" | |
| return 1 | |
| fi | |
| elif command -v npx &> /dev/null; then | |
| if npx --yes secretlint "$target" 2>/dev/null; then | |
| print_success "Secretlint: No secrets detected" | |
| return 0 | |
| else | |
| print_error "Secretlint: Potential secrets found or scan failed" | |
| return 1 | |
| fi | |
| else | |
| print_warning "Secretlint not available, skipping credential scan" | |
| return 0 | |
| fi | |
| } |
🤖 Prompt for AI Agents
In @.agent/scripts/privacy-filter-helper.sh around lines 175 - 206,
run_secretlint currently treats any non-zero result from the npx branch as
"secretlint not available" and returns success; change the npx fallback to first
verify npx exists (e.g., command -v npx) and if absent print_warning and return
0, but if npx is present run npx --yes secretlint "$target" and treat a non-zero
exit as a real failure (print_error "Secretlint: Potential secrets found!" and
return 1) instead of masking it as skipped; update the npx branch in
run_secretlint to explicitly distinguish "npx missing" vs "scan failed"
behaviors.
| # Show before/after for each match | ||
| if command -v rg &> /dev/null; then | ||
| rg -n -e "$pattern" "$file" 2>/dev/null | while IFS= read -r match; do | ||
| local line content redacted | ||
| line=$(echo "$match" | cut -d: -f1) | ||
| content=$(echo "$match" | cut -d: -f2-) | ||
| redacted=$(echo "$content" | sed -E "s/$pattern/[REDACTED]/g") | ||
| echo -e " Line $line:" | ||
| echo -e " ${RED}Before:${NC} ${content:0:80}" | ||
| echo -e " ${GREEN}After:${NC} ${redacted:0:80}" | ||
| done | ||
| fi | ||
| echo "" | ||
| done <<< "$matches" | ||
| fi | ||
| done | ||
|
|
||
| print_info "Run 'privacy-filter-helper.sh apply' to apply redactions" | ||
| return 0 | ||
| } | ||
|
|
||
| # Apply redactions to files | ||
| apply_redactions() { | ||
| local target="${1:-.}" | ||
| local -a patterns | ||
| local changes=0 | ||
|
|
||
| print_header "Applying Privacy Redactions" | ||
| print_warning "This will modify files in place!" | ||
| echo "" | ||
|
|
||
| read -p "Continue? [y/N] " -n 1 -r | ||
| echo "" | ||
| if [[ ! $REPLY =~ ^[Yy]$ ]]; then | ||
| print_info "Aborted" | ||
| return 1 | ||
| fi | ||
|
|
||
| # Load all patterns | ||
| mapfile -t patterns < <(get_all_patterns) | ||
|
|
||
| # Apply redactions | ||
| for pattern in "${patterns[@]}"; do | ||
| local matches | ||
| if command -v rg &> /dev/null; then | ||
| matches=$(rg -l -e "$pattern" "$target" 2>/dev/null || true) | ||
| else | ||
| matches=$(grep -rl -E "$pattern" "$target" 2>/dev/null || true) | ||
| fi | ||
|
|
||
| if [[ -n "$matches" ]]; then | ||
| while IFS= read -r file; do | ||
| # Create backup | ||
| cp "$file" "${file}.privacy-backup" | ||
|
|
||
| # Apply redaction | ||
| if [[ "$(uname)" == "Darwin" ]]; then | ||
| sed -i '' -E "s/$pattern/[REDACTED]/g" "$file" | ||
| else | ||
| sed -i -E "s/$pattern/[REDACTED]/g" "$file" | ||
| fi | ||
|
|
||
| print_success "Redacted: $file" | ||
| changes=$((changes + 1)) | ||
| done <<< "$matches" | ||
| fi | ||
| done | ||
|
|
||
| echo "" | ||
| if [[ $changes -eq 0 ]]; then | ||
| print_info "No changes made" | ||
| else | ||
| print_success "Applied redactions to $changes files" | ||
| print_info "Backup files created with .privacy-backup extension" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, locate and read the file to understand full context
fd "privacy-filter-helper.sh" -t fRepository: marcusquinn/aidevops
Length of output: 103
🏁 Script executed:
# Read the file to see the complete apply_redactions function
head -n 410 .agent/scripts/privacy-filter-helper.sh | tail -n 100Repository: marcusquinn/aidevops
Length of output: 3180
🏁 Script executed:
# Get a better view of the entire apply_redactions function
sed -n '350,410p' .agent/scripts/privacy-filter-helper.shRepository: marcusquinn/aidevops
Length of output: 1765
🏁 Script executed:
# Check if rg supports --passthru by examining rg documentation
rg --help | grep -A 2 "passthru\|replace"Repository: marcusquinn/aidevops
Length of output: 2104
🏁 Script executed:
# Also check the sed behavior with different regex features
# Create a test to see if sed -E handles \b like rg does
cat > /tmp/test_regex.sh << 'EOF'
#!/bin/bash
# Test 1: Check if sed -E and rg handle \b differently
echo "Testing word boundary \\b"
echo "test word testing" > /tmp/test.txt
# rg output (if available)
if command -v rg &> /dev/null; then
echo "rg -E '\\bword\\b' matches:"
rg -E '\bword\b' /tmp/test.txt 2>/dev/null || echo "No match or error"
fi
# sed output
echo "sed -E 's/\\bword\\b/[REDACTED]/g' result:"
sed -E 's/\bword\b/[REDACTED]/g' /tmp/test.txt
echo ""
echo "Testing forward slash in pattern:"
# Test 2: Forward slash in pattern breaking sed
echo "path/to/file.txt" > /tmp/test2.txt
pattern="path/to"
echo "Pattern: $pattern"
echo "Using sed with default delimiter:"
sed -E "s/$pattern/[REDACTED]/g" /tmp/test2.txt 2>&1 || echo "ERROR with default delimiter"
echo "Using sed with pipe delimiter:"
sed -E "s|$pattern|[REDACTED]|g" /tmp/test2.txt 2>&1 && echo "SUCCESS with pipe delimiter"
EOF
bash /tmp/test_regex.shRepository: marcusquinn/aidevops
Length of output: 445
🏁 Script executed:
# Check if there's any pattern definition in the config that uses special characters
grep -n "patterns\|PASSWORD\|SECRET\|regex" .agent/scripts/privacy-filter-helper.sh | head -20Repository: marcusquinn/aidevops
Length of output: 956
🏁 Script executed:
# Look for how patterns are defined or loaded
sed -n '1,100p' .agent/scripts/privacy-filter-helper.sh | grep -A 10 "get_all_patterns\|PRIVACY_PATTERNS"Repository: marcusquinn/aidevops
Length of output: 46
🏁 Script executed:
# Get the DEFAULT_PATTERNS array to see actual pattern content
sed -n '38,135p' .agent/scripts/privacy-filter-helper.shRepository: marcusquinn/aidevops
Length of output: 2501
🏁 Script executed:
# Also check for any extended regex features that might differ between sed and rg
grep -E "\\\\[bBdDsSwW]|\\\\[1-9]" .agent/scripts/privacy-filter-helper.shRepository: marcusquinn/aidevops
Length of output: 467
🏁 Script executed:
# Test if the actual patterns from the script would fail with current sed implementation
cat > /tmp/test_actual_patterns.sh << 'EOF'
#!/bin/bash
# Test patterns from the DEFAULT_PATTERNS array that contain problematic characters
test_file="/tmp/test_patterns.txt"
cat > "$test_file" << 'CONTENT'
Connect to mongodb://user:pass@localhost:27017/dbname
API key: sk-1234567890abcdefghij
Bearer token: Bearer abc.def.ghi
CONTENT
# Test 1: Forward slash patterns (will fail)
echo "=== Testing forward slash pattern (mongodb) ==="
pattern='mongodb(\+srv)?://[^\s]+'
echo "Pattern: $pattern"
echo "Testing sed with default delimiter:"
sed -i -E "s/$pattern/[REDACTED]/g" "$test_file" 2>&1 && echo "SUCCESS" || echo "FAILED (as expected)"
# Restore file
cat > "$test_file" << 'CONTENT'
Connect to mongodb://user:pass@localhost:27017/dbname
API key: sk-1234567890abcdefghij
Bearer token: Bearer abc.def.ghi
CONTENT
# Test 2: Word boundary pattern
echo ""
echo "=== Testing word boundary pattern ==="
pattern='Bearer [a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+'
echo "Pattern: $pattern"
echo "Original line:"
grep "Bearer" "$test_file"
echo "After sed -E (no escaping of slashes):"
sed -E "s/$pattern/[REDACTED]/g" "$test_file" | grep "Bearer" || echo "Pattern processed"
# Test 3: Using pipe delimiter (safer)
echo ""
echo "=== Testing with pipe delimiter ==="
pattern='mongodb(\+srv)?://[^\s]+'
echo "Pattern: $pattern"
sed -E "s|$pattern|[REDACTED]|g" "$test_file" 2>&1 && echo "SUCCESS with pipe delimiter"
grep "mongodb" "$test_file"
EOF
bash /tmp/test_actual_patterns.shRepository: marcusquinn/aidevops
Length of output: 742
🏁 Script executed:
# Verify rg --passthru --replace functionality
echo "Testing rg --passthru --replace:"
test_file="/tmp/test_rg.txt"
cat > "$test_file" << 'EOF'
API key: sk-1234567890abcdefghij
Password: secret123
Normal line
EOF
if command -v rg &> /dev/null; then
echo "File before:"
cat "$test_file"
echo ""
echo "Using rg --passthru --replace:"
rg --passthru -e 'sk-[a-zA-Z0-9]{20,}' --replace '[REDACTED]' "$test_file"
fiRepository: marcusquinn/aidevops
Length of output: 258
🏁 Script executed:
# Verify the backup overwrite issue more explicitly
cat > /tmp/test_backup_logic.sh << 'EOF'
#!/bin/bash
# Simulate the current backup logic
test_dir="/tmp/backup_test"
mkdir -p "$test_dir"
test_file="$test_dir/test.txt"
# Create initial file
echo "Original content" > "$test_file"
echo "Backup creation simulation:"
echo "Initial file:"
cat "$test_file"
# Simulate pattern loop (3 patterns)
for i in 1 2 3; do
cp "$test_file" "${test_file}.privacy-backup"
echo "Pattern $i: Backup created/overwritten"
# Modify file
echo "Modified by pattern $i" >> "$test_file"
done
echo ""
echo "Final backup content (should be from first pattern, but might be overwritten):"
cat "${test_file}.privacy-backup"
echo ""
echo "Final file content:"
cat "$test_file"
EOF
bash /tmp/test_backup_logic.shRepository: marcusquinn/aidevops
Length of output: 481
🏁 Script executed:
# Check if word boundary \b actually appears in patterns used
grep -o "\\\\b" .agent/scripts/privacy-filter-helper.sh | wc -lRepository: marcusquinn/aidevops
Length of output: 65
🏁 Script executed:
# Test if sed -E actually handles \b correctly (spoiler: it doesn't match as word boundary)
cat > /tmp/test_word_boundary.sh << 'EOF'
#!/bin/bash
# Test word boundary with actual IP pattern from script
ip_pattern='\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b'
echo "Testing IPv4 pattern with word boundaries"
echo "Pattern: $ip_pattern"
test_content="IP: 192.168.1.1 and text192.168.1.1text"
echo "Test content: $test_content"
echo ""
echo "Using rg (should match both, respecting word boundaries):"
if command -v rg &> /dev/null; then
echo "$test_content" | rg -o '\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b' 2>&1 || echo "Pattern match result above"
fi
echo ""
echo "Using sed -E (will NOT respect \\b as word boundary):"
echo "$test_content" | sed -E 's/\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/[REDACTED]/g' 2>&1 || echo "Error (expected - sed doesn't support PCRE)"
EOF
bash /tmp/test_word_boundary.shRepository: marcusquinn/aidevops
Length of output: 501
Critical regex incompatibility and backup data loss risks.
The current implementation has multiple failure modes:
-
Forward slashes break sed: Patterns like
mongodb://,postgres://,redis://fail with "unknown option tos'" error because sed interprets the/` as a delimiter. The script dies silently on these patterns. -
Word boundaries unsupported in sed: Patterns using
\b(e.g., IPv4 address detection) fail with "Invalid preceding regular expression" because sed's extended regex doesn't support PCRE word boundaries, while rg does. This causes silent pattern misses in the scan phase but catastrophic errors in apply phase. -
Backups overwritten per pattern: When multiple patterns match the same file, the backup is created fresh for each pattern iteration. If pattern 1 modifies the file, then pattern 2 overwrites the backup—losing the original content before pattern 1.
Use rg --passthru --replace for consistent redaction and create backups once per file, not once per pattern:
Suggested fix
- # Create backup
- cp "$file" "${file}.privacy-backup"
-
- # Apply redaction
- if [[ "$(uname)" == "Darwin" ]]; then
- sed -i '' -E "s/$pattern/[REDACTED]/g" "$file"
- else
- sed -i -E "s/$pattern/[REDACTED]/g" "$file"
- fi
+ # Create backup once per file
+ if [[ ! -f "${file}.privacy-backup" ]]; then
+ cp "$file" "${file}.privacy-backup"
+ fi
+
+ # Apply redaction using the same regex engine as scan
+ if command -v rg &> /dev/null; then
+ rg --passthru -e "$pattern" --replace '[REDACTED]' "$file" > "${file}.privacy-tmp"
+ mv "${file}.privacy-tmp" "$file"
+ else
+ # Fallback: use pipe delimiter to handle forward slashes
+ safe_pattern="${pattern//|/\\|}"
+ if [[ "$(uname)" == "Darwin" ]]; then
+ sed -i '' -E "s|$safe_pattern|[REDACTED]|g" "$file"
+ else
+ sed -i -E "s|$safe_pattern|[REDACTED]|g" "$file"
+ fi
+ fiPer coding guidelines: automation scripts must prioritize reliability and robustness. This implementation fails on existing default patterns and loses original backups.
📝 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.
| # Show before/after for each match | |
| if command -v rg &> /dev/null; then | |
| rg -n -e "$pattern" "$file" 2>/dev/null | while IFS= read -r match; do | |
| local line content redacted | |
| line=$(echo "$match" | cut -d: -f1) | |
| content=$(echo "$match" | cut -d: -f2-) | |
| redacted=$(echo "$content" | sed -E "s/$pattern/[REDACTED]/g") | |
| echo -e " Line $line:" | |
| echo -e " ${RED}Before:${NC} ${content:0:80}" | |
| echo -e " ${GREEN}After:${NC} ${redacted:0:80}" | |
| done | |
| fi | |
| echo "" | |
| done <<< "$matches" | |
| fi | |
| done | |
| print_info "Run 'privacy-filter-helper.sh apply' to apply redactions" | |
| return 0 | |
| } | |
| # Apply redactions to files | |
| apply_redactions() { | |
| local target="${1:-.}" | |
| local -a patterns | |
| local changes=0 | |
| print_header "Applying Privacy Redactions" | |
| print_warning "This will modify files in place!" | |
| echo "" | |
| read -p "Continue? [y/N] " -n 1 -r | |
| echo "" | |
| if [[ ! $REPLY =~ ^[Yy]$ ]]; then | |
| print_info "Aborted" | |
| return 1 | |
| fi | |
| # Load all patterns | |
| mapfile -t patterns < <(get_all_patterns) | |
| # Apply redactions | |
| for pattern in "${patterns[@]}"; do | |
| local matches | |
| if command -v rg &> /dev/null; then | |
| matches=$(rg -l -e "$pattern" "$target" 2>/dev/null || true) | |
| else | |
| matches=$(grep -rl -E "$pattern" "$target" 2>/dev/null || true) | |
| fi | |
| if [[ -n "$matches" ]]; then | |
| while IFS= read -r file; do | |
| # Create backup | |
| cp "$file" "${file}.privacy-backup" | |
| # Apply redaction | |
| if [[ "$(uname)" == "Darwin" ]]; then | |
| sed -i '' -E "s/$pattern/[REDACTED]/g" "$file" | |
| else | |
| sed -i -E "s/$pattern/[REDACTED]/g" "$file" | |
| fi | |
| print_success "Redacted: $file" | |
| changes=$((changes + 1)) | |
| done <<< "$matches" | |
| fi | |
| done | |
| echo "" | |
| if [[ $changes -eq 0 ]]; then | |
| print_info "No changes made" | |
| else | |
| print_success "Applied redactions to $changes files" | |
| print_info "Backup files created with .privacy-backup extension" | |
| # Create backup once per file | |
| if [[ ! -f "${file}.privacy-backup" ]]; then | |
| cp "$file" "${file}.privacy-backup" | |
| fi | |
| # Apply redaction using the same regex engine as scan | |
| if command -v rg &> /dev/null; then | |
| rg --passthru -e "$pattern" --replace '[REDACTED]' "$file" > "${file}.privacy-tmp" | |
| mv "${file}.privacy-tmp" "$file" | |
| else | |
| # Fallback: use pipe delimiter to handle forward slashes | |
| safe_pattern="${pattern//|/\\|}" | |
| if [[ "$(uname)" == "Darwin" ]]; then | |
| sed -i '' -E "s|$safe_pattern|[REDACTED]|g" "$file" | |
| else | |
| sed -i -E "s|$safe_pattern|[REDACTED]|g" "$file" | |
| fi | |
| fi | |
| print_success "Redacted: $file" | |
| changes=$((changes + 1)) |
🤖 Prompt for AI Agents
In @.agent/scripts/privacy-filter-helper.sh around lines 326 - 399,
apply_redactions currently uses sed per-pattern (breaking on / delimiters and
\b, and recreates backups per pattern); change it to use ripgrep's replace to
perform safe, delimiter-free replacements and create a single backup per file:
in apply_redactions (and the matches loop) detect if command -v rg; for each
file create its "${file}.privacy-backup" only once (before any replacements) and
then for replacement run a pipeline applying all patterns via rg --passthru
--replace (iteratively feed the file through rg --passthru --replace -e
"$pattern" --replace '[REDACTED]' into a temp file, or construct a single stream
of replacements) and atomically move the temp into place; if rg is not
available, fallback to perl -pe using s{pattern}[REDACTED}g with proper escaping
so / and \b work; ensure patterns from get_all_patterns are quoted/handled
safely and remove the per-pattern cp "$file" "${file}.privacy-backup" so backup
is only created once per file.
| # Colors for output | ||
| readonly GREEN='\033[0;32m' | ||
| readonly BLUE='\033[0;34m' | ||
| readonly YELLOW='\033[1;33m' | ||
| readonly RED='\033[0;31m' | ||
| readonly PURPLE='\033[0;35m' | ||
| readonly CYAN='\033[0;36m' | ||
| readonly NC='\033[0m' # No Color |
There was a problem hiding this comment.
Remove unused CYAN to keep static checks clean.
Static analysis flags CYAN as unused. Remove it or use it in output.
🧹 Proposed fix
-readonly CYAN='\033[0;36m'📝 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.
| # Colors for output | |
| readonly GREEN='\033[0;32m' | |
| readonly BLUE='\033[0;34m' | |
| readonly YELLOW='\033[1;33m' | |
| readonly RED='\033[0;31m' | |
| readonly PURPLE='\033[0;35m' | |
| readonly CYAN='\033[0;36m' | |
| readonly NC='\033[0m' # No Color | |
| # Colors for output | |
| readonly GREEN='\033[0;32m' | |
| readonly BLUE='\033[0;34m' | |
| readonly YELLOW='\033[1;33m' | |
| readonly RED='\033[0;31m' | |
| readonly PURPLE='\033[0;35m' | |
| readonly NC='\033[0m' # No Color |
🧰 Tools
🪛 GitHub Check: Codacy Static Code Analysis
[warning] 45-45: .agent/scripts/self-improve-helper.sh#L45
CYAN appears unused. Verify use (or export if used externally).
🤖 Prompt for AI Agents
In @.agent/scripts/self-improve-helper.sh around lines 39 - 46, The CYAN color
constant (readonly CYAN='\033[0;36m') is defined but unused; remove that line
from the color definitions in .agent/scripts/self-improve-helper.sh (the block
containing GREEN, BLUE, YELLOW, RED, PURPLE, CYAN, NC) so static analysis no
longer flags an unused variable, or alternatively use CYAN in any output helper
function (e.g., the script's logging/echo calls) if you prefer to keep it.
| prompt="You are analyzing failure patterns to generate agent improvements. | ||
|
|
||
| ## Analysis Data | ||
| $(echo "$analysis" | jq -c '.') | ||
|
|
||
| ## Task | ||
| Based on the failures without solutions, propose specific improvements to: | ||
| 1. Agent instructions (AGENTS.md or subagents) | ||
| 2. Helper scripts | ||
| 3. Workflows | ||
|
|
||
| For each proposal, provide: | ||
| - File to modify | ||
| - Specific change (as a diff or description) | ||
| - Expected impact | ||
| - Test prompt to validate | ||
|
|
||
| Output as JSON array: | ||
| [ | ||
| { | ||
| \"file\": \"path/to/file\", | ||
| \"change_type\": \"edit|add|delete\", | ||
| \"description\": \"What to change\", | ||
| \"diff\": \"Optional diff content\", | ||
| \"impact\": \"Expected improvement\", | ||
| \"test_prompt\": \"Prompt to validate this works\" | ||
| } | ||
| ]" | ||
|
|
||
| if [[ "$dry_run" == true ]]; then | ||
| log_info "[DRY RUN] Would send prompt to OpenCode session" | ||
| echo "" | ||
| echo "Prompt preview:" | ||
| echo "$prompt" | head -30 | ||
| echo "..." | ||
| delete_session "$session_id" | ||
| return 0 | ||
| fi | ||
|
|
||
| log_info "Generating improvement proposals..." | ||
|
|
||
| local response | ||
| response=$(send_prompt "$session_id" "$prompt") | ||
|
|
||
| # Extract proposals from response | ||
| local proposals | ||
| proposals=$(echo "$response" | jq -r '.parts[] | select(.type == "text") | .text' 2>/dev/null | grep -o '\[.*\]' | head -1 || echo "[]") | ||
|
|
||
| if [[ "$proposals" == "[]" || -z "$proposals" ]]; then | ||
| log_warn "No proposals generated. Response may need manual review." | ||
| echo "$response" | jq '.' 2>/dev/null || echo "$response" | ||
| delete_session "$session_id" | ||
| return 1 | ||
| fi |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's look at the file structure and the specific lines in question
wc -l .agent/scripts/self-improve-helper.shRepository: marcusquinn/aidevops
Length of output: 105
🏁 Script executed:
# Read the section around lines 281-334
sed -n '270,345p' .agent/scripts/self-improve-helper.sh | cat -nRepository: marcusquinn/aidevops
Length of output: 2826
🏁 Script executed:
# Let's also check the broader context to understand how proposals are used
grep -n "proposals=" .agent/scripts/self-improve-helper.sh | head -10Repository: marcusquinn/aidevops
Length of output: 281
🏁 Script executed:
# Test the grep pattern with multi-line JSON
cat > /tmp/test_extract.sh << 'EOF'
#!/bin/bash
# Simulate a response with multi-line JSON
response_multiline='Some text before
[
{
"file": "path/to/file",
"change_type": "edit"
}
]
More text after'
echo "=== Test 1: Multi-line JSON ==="
echo "Input:"
echo "$response_multiline"
echo ""
echo "Using grep -o '\[.*\]':"
echo "$response_multiline" | grep -o '\[.*\]' || echo "NO MATCH"
echo ""
# Test with single-line JSON
response_singleline='Some text [{"file":"path","change_type":"edit"}] more text'
echo "=== Test 2: Single-line JSON ==="
echo "Input:"
echo "$response_singleline"
echo ""
echo "Using grep -o '\[.*\]':"
echo "$response_singleline" | grep -o '\[.*\]' || echo "NO MATCH"
echo ""
# Test with greedy capture issue
response_greedy='text [{"a":1}] middle [{"b":2}] end'
echo "=== Test 3: Multiple JSON arrays (greedy issue) ==="
echo "Input:"
echo "$response_greedy"
echo ""
echo "Using grep -o '\[.*\]':"
echo "$response_greedy" | grep -o '\[.*\]' || echo "NO MATCH"
echo ""
# Test the proposed fix
echo "=== Test 4: Proposed fix with multi-line ==="
echo "$response_multiline" | printf '%s\n' "$(cat)" | jq -c '.' 2>/dev/null || echo "Failed - invalid JSON"
EOF
bash /tmp/test_extract.shRepository: marcusquinn/aidevops
Length of output: 615
🏁 Script executed:
# Test the improved extraction approach
cat > /tmp/test_improved.sh << 'EOF'
#!/bin/bash
# Simulate actual response structure as per OpenCode API
response='{"parts":[{"type":"text","text":"Here are the proposals:\n\n[\n {\"file\":\"AGENTS.md\",\"change_type\":\"edit\",\"description\":\"Update instructions\",\"diff\":\"test\",\"impact\":\"Better performance\",\"test_prompt\":\"test this\"}\n]\n\nThese are good proposals."}]}'
echo "=== Original approach (grep greedy) ==="
proposals=$(echo "$response" | jq -r '.parts[] | select(.type == "text") | .text' 2>/dev/null | grep -o '\[.*\]' | head -1 || echo "[]")
echo "Result: $proposals"
echo ""
echo "Validation with jq:"
echo "$proposals" | jq '.' 2>&1 | head -5
echo ""
echo "=== Improved approach (split + jq validate) ==="
proposals_text=$(echo "$response" | jq -r '.parts[] | select(.type == "text") | .text' 2>/dev/null)
proposals=$(echo "$proposals_text" | jq -c '.' 2>/dev/null || echo "[]")
echo "Result: $proposals"
echo ""
EOF
bash /tmp/test_improved.shRepository: marcusquinn/aidevops
Length of output: 194
🏁 Script executed:
# Check if there are any other JSON extraction patterns in the file
grep -n "grep.*\[.*\]" .agent/scripts/self-improve-helper.shRepository: marcusquinn/aidevops
Length of output: 208
🏁 Script executed:
# Check what happens when proposals is used downstream - line 70
sed -n '68,80p' .agent/scripts/self-improve-helper.sh | cat -nRepository: marcusquinn/aidevops
Length of output: 455
Fix JSON extraction to handle multi-line responses and validate with jq.
The current grep -o '\[.*\]' pattern fails silently for multi-line JSON (grep's . doesn't match newlines), causing proposals to return empty and the function to incorrectly report "No proposals generated". This breaks reliability when the LLM returns properly formatted multi-line JSON per the prompt instructions. Additionally, the greedy regex creates corruption risk if multiple JSON structures are present.
Fix: Enforce JSON-only output in the prompt, then extract directly with jq validation:
🔧 Recommended fix
-Output as JSON array:
+Return ONLY the JSON array with no additional prose:
@@
- proposals=$(echo "$response" | jq -r '.parts[] | select(.type == "text") | .text' 2>/dev/null | grep -o '\[.*\]' | head -1 || echo "[]")
+ proposals=$(echo "$response" | jq -r '.parts[] | select(.type == "text") | .text' 2>/dev/null | jq -s 'if . == [""] then "[]" else (if .[0] | startswith("[") then .[0] else "[]" end) end | fromjson' 2>/dev/null || echo "[]")Or simpler—if enforcing JSON-only output works:
+ proposals=$(echo "$response" | jq -r '.parts[] | select(.type == "text") | .text' 2>/dev/null | jq -c '.' 2>/dev/null || echo "[]")Per coding guidelines (Reliability, robustness, proper error recovery): Silent failures on multi-line responses violate these requirements.
🤖 Prompt for AI Agents
In @.agent/scripts/self-improve-helper.sh around lines 281 - 334, The proposals
extraction fails for multi-line JSON because proposals=$(echo "$response" | jq
-r '.parts[] | select(.type == "text") | .text' 2>/dev/null | grep -o '\[.*\]' |
head -1 || echo "[]") uses a single-line grep and a greedy regex; change the
extraction to parse the full response with jq and validate with jq --exit-status
to ensure JSON-only output: call send_prompt as before, capture response, then
use jq to locate and parse the JSON array (e.g., filter .parts[][].text or
assemble candidate strings) and run jq . to validate; if validation fails, log
the raw response and return error; update the variable proposals and the error
branch that checks proposals (the log_warn block) to handle empty/invalid JSON
returned by jq and to avoid silent failures from grep.
| ## TypeScript SDK | ||
|
|
||
| ### Installation | ||
|
|
||
| ```bash | ||
| npm install @opencode-ai/sdk | ||
| ``` | ||
|
|
||
| ### Creating a Client | ||
|
|
||
| ```typescript | ||
| import { createOpencode, createOpencodeClient } from "@opencode-ai/sdk" | ||
|
|
||
| // Option 1: Start server + client together | ||
| const { client, server } = await createOpencode({ | ||
| port: 4096, | ||
| hostname: "127.0.0.1", | ||
| config: { | ||
| model: "anthropic/claude-sonnet-4-20250514", | ||
| }, | ||
| }) | ||
|
|
||
| // Option 2: Connect to existing server | ||
| const client = createOpencodeClient({ | ||
| baseUrl: "http://localhost:4096", | ||
| }) | ||
| ``` | ||
|
|
||
| ### Session Management | ||
|
|
||
| ```typescript | ||
| // Create a new session | ||
| const session = await client.session.create({ | ||
| body: { title: "My automated task" }, | ||
| }) | ||
|
|
||
| // List all sessions | ||
| const sessions = await client.session.list() | ||
|
|
||
| // Get session details | ||
| const details = await client.session.get({ | ||
| path: { id: session.data.id }, | ||
| }) | ||
|
|
||
| // Delete a session | ||
| await client.session.delete({ | ||
| path: { id: session.data.id }, | ||
| }) | ||
| ``` | ||
|
|
||
| ### Sending Prompts | ||
|
|
||
| ```typescript | ||
| // Synchronous prompt (waits for full response) | ||
| const result = await client.session.prompt({ | ||
| path: { id: session.data.id }, | ||
| body: { | ||
| model: { | ||
| providerID: "anthropic", | ||
| modelID: "claude-sonnet-4-20250514", | ||
| }, | ||
| parts: [{ type: "text", text: "Explain this codebase structure" }], | ||
| }, | ||
| }) | ||
|
|
||
| console.log(result.data.parts) // AI response parts | ||
|
|
||
| // Asynchronous prompt (fire and forget) | ||
| await client.session.promptAsync({ | ||
| path: { id: session.data.id }, | ||
| body: { | ||
| parts: [{ type: "text", text: "Run the test suite" }], | ||
| }, | ||
| }) | ||
| // Returns 204 No Content immediately | ||
| // Monitor via SSE events | ||
| ``` | ||
|
|
||
| ### Context Injection (No Reply) | ||
|
|
||
| ```typescript | ||
| // Inject context without triggering AI response | ||
| await client.session.prompt({ | ||
| path: { id: session.data.id }, | ||
| body: { | ||
| noReply: true, | ||
| parts: [ | ||
| { | ||
| type: "text", | ||
| text: "Context: This project uses TypeScript and Bun runtime.", | ||
| }, | ||
| ], | ||
| }, | ||
| }) | ||
| ``` | ||
|
|
||
| ### Real-Time Events (SSE) | ||
|
|
||
| ```typescript | ||
| // Subscribe to server events | ||
| const events = await client.event.subscribe() | ||
|
|
||
| for await (const event of events.stream) { | ||
| switch (event.type) { | ||
| case "session.message": | ||
| console.log("New message:", event.properties) | ||
| break | ||
| case "session.status": | ||
| console.log("Status change:", event.properties) | ||
| break | ||
| case "tool.call": | ||
| console.log("Tool invoked:", event.properties) | ||
| break | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Direct HTTP API | ||
|
|
||
| ### Create Session | ||
|
|
||
| ```bash | ||
| curl -X POST http://localhost:4096/session \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{"title": "API Test Session"}' | ||
| ``` | ||
|
|
||
| ### Send Prompt (Sync) | ||
|
|
||
| ```bash | ||
| curl -X POST http://localhost:4096/session/{session_id}/message \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{ | ||
| "model": { | ||
| "providerID": "anthropic", | ||
| "modelID": "claude-sonnet-4-20250514" | ||
| }, | ||
| "parts": [{"type": "text", "text": "Hello!"}] | ||
| }' | ||
| ``` | ||
|
|
||
| ### Send Prompt (Async) | ||
|
|
||
| ```bash | ||
| curl -X POST http://localhost:4096/session/{session_id}/prompt_async \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{ | ||
| "parts": [{"type": "text", "text": "Run tests in background"}] | ||
| }' | ||
| # Returns 204 immediately | ||
| ``` | ||
|
|
||
| ### Subscribe to Events | ||
|
|
||
| ```bash | ||
| curl -N http://localhost:4096/event | ||
| # SSE stream - first event is server.connected | ||
| ``` | ||
|
|
||
| ### Execute Slash Command | ||
|
|
||
| ```bash | ||
| curl -X POST http://localhost:4096/session/{session_id}/command \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{ | ||
| "command": "remember", | ||
| "arguments": "This pattern worked for async processing" | ||
| }' | ||
| ``` | ||
|
|
||
| ### Run Shell Command | ||
|
|
||
| ```bash | ||
| curl -X POST http://localhost:4096/session/{session_id}/shell \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{ | ||
| "agent": "default", | ||
| "command": "npm test" | ||
| }' | ||
| ``` | ||
|
|
||
| ## Use Cases for aidevops | ||
|
|
||
| ### 1. Parallel Agent Orchestration | ||
|
|
||
| Run multiple AI sessions concurrently for different tasks: | ||
|
|
||
| ```typescript | ||
| import { createOpencodeClient } from "@opencode-ai/sdk" | ||
|
|
||
| const client = createOpencodeClient({ baseUrl: "http://localhost:4096" }) | ||
|
|
||
| // Create parallel sessions for different tasks | ||
| const [codeReview, docGen, testGen] = await Promise.all([ | ||
| client.session.create({ body: { title: "Code Review" } }), | ||
| client.session.create({ body: { title: "Documentation" } }), | ||
| client.session.create({ body: { title: "Test Generation" } }), | ||
| ]) | ||
|
|
||
| // Dispatch tasks in parallel | ||
| await Promise.all([ | ||
| client.session.promptAsync({ | ||
| path: { id: codeReview.data.id }, | ||
| body: { parts: [{ type: "text", text: "Review src/auth.ts for security issues" }] }, | ||
| }), | ||
| client.session.promptAsync({ | ||
| path: { id: docGen.data.id }, | ||
| body: { parts: [{ type: "text", text: "Generate API documentation for src/api/" }] }, | ||
| }), | ||
| client.session.promptAsync({ | ||
| path: { id: testGen.data.id }, | ||
| body: { parts: [{ type: "text", text: "Generate unit tests for src/utils/" }] }, | ||
| }), | ||
| ]) | ||
| ``` | ||
|
|
||
| ### 2. Voice Dispatch (VoiceInk/iOS Shortcut) | ||
|
|
||
| Send voice transcriptions to OpenCode: | ||
|
|
||
| ```bash | ||
| #!/bin/bash | ||
| # voice-dispatch.sh - Called by VoiceInk or iOS Shortcut | ||
|
|
||
| TRANSCRIPTION="$1" | ||
| SESSION_ID="${OPENCODE_SESSION_ID:-default}" | ||
| SERVER="http://localhost:4096" | ||
|
|
||
| curl -X POST "$SERVER/session/$SESSION_ID/prompt_async" \ | ||
| -H "Content-Type: application/json" \ | ||
| -d "{\"parts\": [{\"type\": \"text\", \"text\": \"$TRANSCRIPTION\"}]}" | ||
| ``` | ||
|
|
||
| ### 3. Automated Agent Testing | ||
|
|
||
| Test agent changes in isolated sessions: | ||
|
|
||
| ```typescript | ||
| async function testAgentChange(testPrompt: string, expectedPattern: RegExp) { | ||
| const client = createOpencodeClient({ baseUrl: "http://localhost:4096" }) | ||
|
|
||
| // Create isolated test session | ||
| const session = await client.session.create({ | ||
| body: { title: `Test: ${Date.now()}` }, | ||
| }) | ||
|
|
||
| try { | ||
| // Send test prompt | ||
| const result = await client.session.prompt({ | ||
| path: { id: session.data.id }, | ||
| body: { | ||
| parts: [{ type: "text", text: testPrompt }], | ||
| }, | ||
| }) | ||
|
|
||
| // Extract text from response | ||
| const responseText = result.data.parts | ||
| .filter((p) => p.type === "text") | ||
| .map((p) => p.text) | ||
| .join("\n") | ||
|
|
||
| // Validate response | ||
| const passed = expectedPattern.test(responseText) | ||
| return { passed, response: responseText } | ||
| } finally { | ||
| // Cleanup | ||
| await client.session.delete({ path: { id: session.data.id } }) | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### 4. Self-Improving Agent Loop | ||
|
|
||
| Query memory, generate improvements, test in isolated session: | ||
|
|
||
| ```typescript | ||
| async function selfImproveLoop() { | ||
| const client = createOpencodeClient({ baseUrl: "http://localhost:4096" }) | ||
|
|
||
| // 1. Review phase - analyze memory for patterns | ||
| const reviewSession = await client.session.create({ | ||
| body: { title: "Self-Improve: Review" }, | ||
| }) | ||
|
|
||
| const analysis = await client.session.prompt({ | ||
| path: { id: reviewSession.data.id }, | ||
| body: { | ||
| parts: [ | ||
| { | ||
| type: "text", | ||
| text: `Analyze recent memory entries for failure patterns: | ||
|
|
||
| /recall --type FAILURE --recent 20 | ||
|
|
||
| Identify gaps where we failed but don't have solutions. | ||
| Output as JSON: { gaps: [{ pattern, frequency, suggestion }] }`, | ||
| }, | ||
| ], | ||
| }, | ||
| }) | ||
|
|
||
| // 2. Refine phase - generate improvements | ||
| const refineSession = await client.session.create({ | ||
| body: { title: "Self-Improve: Refine" }, | ||
| }) | ||
|
|
||
| const improvements = await client.session.prompt({ | ||
| path: { id: refineSession.data.id }, | ||
| body: { | ||
| parts: [ | ||
| { | ||
| type: "text", | ||
| text: `Based on these gaps, propose agent improvements: | ||
| ${JSON.stringify(analysis.data)} | ||
|
|
||
| Generate specific edits to agent files. Use worktree isolation.`, | ||
| }, | ||
| ], | ||
| }, | ||
| }) | ||
|
|
||
| // 3. Test phase - validate in isolated session | ||
| const testSession = await client.session.create({ | ||
| body: { title: "Self-Improve: Test" }, | ||
| }) | ||
|
|
||
| // Run test prompts against improved agents... | ||
|
|
||
| // 4. PR phase - create PR if tests pass (with privacy filter) | ||
| } | ||
| ``` | ||
|
|
||
| ### 5. CI/CD Integration | ||
|
|
||
| Trigger AI analysis from GitHub Actions: | ||
|
|
||
| ```yaml | ||
| # .github/workflows/ai-review.yml | ||
| name: AI Code Review | ||
|
|
||
| on: | ||
| pull_request: | ||
| types: [opened, synchronize] | ||
|
|
||
| jobs: | ||
| ai-review: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Start OpenCode Server | ||
| run: | | ||
| opencode serve --port 4096 & | ||
| sleep 5 | ||
|
|
||
| - name: Run AI Review | ||
| run: | | ||
| SESSION=$(curl -s -X POST http://localhost:4096/session \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{"title": "PR Review"}' | jq -r '.id') | ||
|
|
||
| curl -X POST "http://localhost:4096/session/$SESSION/message" \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{ | ||
| "parts": [{ | ||
| "type": "text", | ||
| "text": "Review the changes in this PR for security issues and code quality. Output as markdown." | ||
| }] | ||
| }' | jq -r '.parts[0].text' > review.md | ||
|
|
||
| - name: Post Review Comment | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const fs = require('fs') | ||
| const review = fs.readFileSync('review.md', 'utf8') | ||
| github.rest.issues.createComment({ | ||
| issue_number: context.issue.number, | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| body: review | ||
| }) | ||
| ``` | ||
|
|
There was a problem hiding this comment.
Move deep API/SDK examples to authoritative sources.
Lines 90‑473 embed extensive TS/Bash/YAML examples. Keep this doc as an overview and point to authoritative sources (official docs or repo scripts with file:line references) rather than inline blocks.
As per coding guidelines: .agent/**/*.md: Apply progressive disclosure pattern by using pointers to subagents rather than including inline content in agent documentation; Include code examples only when authoritative; use file:line references to point to actual implementation instead of inline code snippets.
🤖 Prompt for AI Agents
In @.agent/tools/ai-assistants/opencode-server.md around lines 90 - 473, The
"TypeScript SDK" and subsequent long example sections (e.g., headings "Creating
a Client", "Session Management", "Sending Prompts", "Direct HTTP API", and all
numbered use-case examples) are too large for this agent doc; replace the
embedded TS/Bash/YAML blocks with short overview text and explicit pointers to
the authoritative examples and implementation (e.g., link or repo reference to
the SDK README and the server/example scripts), and move the full code samples
out to those canonical files; keep only a one-line minimal snippet or CLI
example where necessary and add "See: [authoritative doc or file:line]"
references for "createOpencode/createOpencodeClient", session methods
(session.create, session.prompt/promptAsync), event.subscribe, and the CI YAML
so readers are directed to the real source.
| ## Usage | ||
|
|
||
| ### Scan for Issues | ||
|
|
||
| ```bash | ||
| # Scan current directory | ||
| privacy-filter-helper.sh scan | ||
|
|
||
| # Scan specific path | ||
| privacy-filter-helper.sh scan ./src | ||
|
|
||
| # Scan staged changes only | ||
| git diff --cached --name-only | xargs privacy-filter-helper.sh scan | ||
| ``` | ||
|
|
||
| ### Preview Redactions | ||
|
|
||
| ```bash | ||
| # See what would be redacted (dry-run) | ||
| privacy-filter-helper.sh filter | ||
|
|
||
| # Preview specific files | ||
| privacy-filter-helper.sh filter ./config | ||
| ``` | ||
|
|
||
| ### Apply Redactions | ||
|
|
||
| ```bash | ||
| # Apply redactions (creates .privacy-backup files) | ||
| privacy-filter-helper.sh apply | ||
|
|
||
| # Review and commit | ||
| git diff | ||
| git add -p | ||
| ``` | ||
|
|
||
| ## Detected Patterns | ||
|
|
||
| ### Credentials | ||
|
|
||
| | Pattern | Example | | ||
| |---------|---------| | ||
| | API keys | `sk-abc123...`, `pk-xyz789...` | | ||
| | AWS keys | `AKIAIOSFODNN7EXAMPLE` | | ||
| | GitHub tokens | `ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` | | ||
| | Stripe keys | `sk_live_...`, `pk_test_...` | | ||
| | Slack tokens | `xoxb-...` | | ||
| | JWT tokens | `eyJhbGciOiJIUzI1NiIs...` | | ||
| | Bearer tokens | `Bearer eyJ...` | | ||
|
|
||
| ### Personal Information | ||
|
|
||
| | Pattern | Example | | ||
| |---------|---------| | ||
| | Email addresses | `user@example.com` | | ||
| | Home paths | `/Users/john/`, `/home/jane/` | | ||
| | Windows paths | `C:\Users\admin\` | | ||
|
|
||
| ### Internal URLs | ||
|
|
||
| | Pattern | Example | | ||
| |---------|---------| | ||
| | Localhost | `localhost:3000`, `127.0.0.1:8080` | | ||
| | Database URLs | `mongodb://user:pass@host/db` | | ||
| | Internal domains | Custom patterns via config | | ||
|
|
||
| ### Private Keys | ||
|
|
||
| | Pattern | Example | | ||
| |---------|---------| | ||
| | RSA keys | `-----BEGIN RSA PRIVATE KEY-----` | | ||
| | EC keys | `-----BEGIN EC PRIVATE KEY-----` | | ||
| | OpenSSH keys | `-----BEGIN OPENSSH PRIVATE KEY-----` | | ||
|
|
||
| ## Custom Patterns | ||
|
|
||
| ### Global Patterns | ||
|
|
||
| Add patterns that apply to all projects: | ||
|
|
||
| ```bash | ||
| # Add a pattern | ||
| privacy-filter-helper.sh patterns add 'mycompany\.internal' | ||
|
|
||
| # Edit patterns file | ||
| privacy-filter-helper.sh patterns edit | ||
| ``` | ||
|
|
||
| Location: `~/.aidevops/config/privacy-patterns.txt` | ||
|
|
||
| ### Project Patterns | ||
|
|
||
| Add patterns specific to a project: | ||
|
|
||
| ```bash | ||
| # Add project pattern | ||
| privacy-filter-helper.sh patterns add-project 'staging\.example\.com' | ||
|
|
||
| # Edit project patterns | ||
| privacy-filter-helper.sh patterns edit-project | ||
| ``` | ||
|
|
||
| Location: `.aidevops/privacy-patterns.txt` | ||
|
|
||
| ### Pattern Format | ||
|
|
||
| Patterns use POSIX extended regular expressions: | ||
|
|
||
| ```text | ||
| # Comments start with # | ||
| # Each line is a regex pattern | ||
|
|
||
| # Internal domains | ||
| staging\.mycompany\.com | ||
| dev\.mycompany\.com | ||
|
|
||
| # Project-specific secrets | ||
| MY_PROJECT_[A-Z]+_KEY | ||
|
|
||
| # Custom usernames | ||
| (john|jane|admin)@mycompany\.com | ||
| ``` | ||
|
|
||
| ## Integration with Self-Improving Agents | ||
|
|
||
| The privacy filter is mandatory in the PR phase (t116.4) of the self-improving agent system: | ||
|
|
||
| ```bash | ||
| # In self-improve-helper.sh pr command: | ||
|
|
||
| # 1. Run privacy filter | ||
| if ! privacy-filter-helper.sh scan "$worktree_path"; then | ||
| echo "Privacy issues detected. Review and fix before PR." | ||
| exit 1 | ||
| fi | ||
|
|
||
| # 2. Show redacted diff for approval | ||
| privacy-filter-helper.sh filter "$worktree_path" | ||
| read -p "Approve PR creation? [y/N] " approval | ||
|
|
||
| # 3. Create PR only if approved | ||
| if [[ "$approval" == "y" ]]; then | ||
| gh pr create ... | ||
| fi | ||
| ``` | ||
|
|
||
| ## Integration with Git Hooks | ||
|
|
||
| Add to pre-commit hook for automatic scanning: | ||
|
|
||
| ```bash | ||
| # .git/hooks/pre-commit | ||
| #!/bin/bash | ||
|
|
||
| # Run privacy filter on staged files | ||
| staged_files=$(git diff --cached --name-only) | ||
| if [[ -n "$staged_files" ]]; then | ||
| echo "$staged_files" | xargs ~/.aidevops/agents/scripts/privacy-filter-helper.sh scan | ||
| if [[ $? -ne 0 ]]; then | ||
| echo "Privacy issues detected. Fix before committing." | ||
| exit 1 | ||
| fi | ||
| fi | ||
| ``` | ||
|
|
||
| ## Secretlint Integration | ||
|
|
||
| The privacy filter uses Secretlint for credential detection: | ||
|
|
||
| ```bash | ||
| # Install secretlint | ||
| npm install -g secretlint @secretlint/secretlint-rule-preset-recommend | ||
|
|
||
| # Or use npx (automatic) | ||
| # The filter falls back to npx if secretlint isn't installed | ||
| ``` | ||
|
|
||
| Secretlint provides more comprehensive credential detection than regex patterns alone. |
There was a problem hiding this comment.
Collapse detailed CLI walkthroughs into pointers to the helper script.
Lines 44‑221 include extensive command sequences. Please reference .agent/scripts/privacy-filter-helper.sh with file:line pointers and keep this doc as a concise overview.
As per coding guidelines: .agent/**/*.md: Apply progressive disclosure pattern by using pointers to subagents rather than including inline content in agent documentation; Include code examples only when authoritative; use file:line references to point to actual implementation instead of inline code snippets.
🤖 Prompt for AI Agents
In @.agent/tools/security/privacy-filter.md around lines 44 - 221, Collapse the
long CLI walkthrough in .agent/tools/security/privacy-filter.md (section
starting at the Usage header with many command examples) into a concise overview
that points readers to the actual implementation script
.agent/scripts/privacy-filter-helper.sh with file:line references for the
relevant functions/flags (e.g., the scan, filter, apply, patterns, and patterns
add-project handlers inside privacy-filter-helper.sh); remove the inline
multi-line command blocks and retain only one brief example for authoritative
usage, plus explicit file:line pointers to the helper script where the full
commands and behavior live, and ensure the "Integration with Self-Improving
Agents" and "Git Hooks" sections reference the specific functions/lines in
privacy-filter-helper.sh instead of embedding full scripts.
| 1. Review the pattern causing the match | ||
| 2. Add an exception to `.aidevops/privacy-patterns.txt`: | ||
|
|
||
| ```text | ||
| # Exclude test fixtures | ||
| !test/fixtures/ | ||
| ``` |
There was a problem hiding this comment.
The “!pattern” exclusion example isn’t supported by the helper.
Line 229‑235 suggests negation (!test/fixtures/), but privacy-filter-helper.sh treats every line as a positive regex, so this won’t exclude anything. Either implement negation support or update the doc to a supported workaround.
✍️ Suggested doc tweak
-2. Add an exception to `.aidevops/privacy-patterns.txt`:
-
-```text
-# Exclude test fixtures
-!test/fixtures/
-```
+2. Narrow the matching regex or move fixtures under ignored paths (e.g., `.gitignore`).
+ Note: negation patterns (`!`) are not currently supported by privacy-filter-helper.sh.🤖 Prompt for AI Agents
In @.agent/tools/security/privacy-filter.md around lines 229 - 235, The
documentation shows a negation pattern (!test/fixtures/) that
privacy-filter-helper.sh does not support; update .aidevops/privacy-patterns.txt
examples and the privacy-filter.md instructions to remove the negation example
and instead show a supported workaround (e.g., narrow the regex or move fixtures
to ignored paths like .gitignore) and add an explicit note that
privacy-filter-helper.sh treats every line as a positive regex and does not
support leading "!" negation; reference the helper script name
privacy-filter-helper.sh and the patterns file .aidevops/privacy-patterns.txt so
reviewers can locate and edit the offending example.



Summary
This PR implements three related tasks from the self-improving agent system plan:
Changes
OpenCode Server Documentation (t115)
tools/ai-assistants/opencode-server.mdwith comprehensive API docsPrivacy Filter (t117)
privacy-filter-helper.shwith scan/filter/apply/patterns commandstools/security/privacy-filter.mddocumentationSelf-Improving Agent System (t116)
self-improve-helper.shwith analyze/refine/test/pr commandsaidevops/self-improving-agents.mddocumentationFiles Changed
Testing
Related
Summary by CodeRabbit
Release Notes
New Features
Documentation