Skip to content

Implement file writing for OpenClaw plugin#5

Merged
KHAEntertainment merged 8 commits intomasterfrom
claude-plugin-v2
Mar 19, 2026
Merged

Implement file writing for OpenClaw plugin#5
KHAEntertainment merged 8 commits intomasterfrom
claude-plugin-v2

Conversation

@KHAEntertainment
Copy link
Copy Markdown
Owner

@KHAEntertainment KHAEntertainment commented Mar 19, 2026

Summary

Implements Traycer's recommendation from issue #2 to add file writing capability to the OpenClaw Grok Swarm plugin.

Changes

Files Modified

  • src/bridge/grok_bridge.py - Added --write-files, --output-dir args + parse_and_write_files()
  • src/bridge/index.js - Added writeFiles, outputDir options, forwards to Python
  • src/plugin/index.ts - Added write_files, output_dir to schema; respects defaultOutputDir
  • src/plugin/openclaw.plugin.json - Added defaultOutputDir config property
  • README.md - Documented new parameters and file writing patterns

Features

Supported File Path Patterns

  1. Language tag with path: ```typescript:src/auth/login.ts`
  2. Comment marker: // FILE: src/auth/login.ts before a fenced block
  3. Python comment marker: # FILE: path/to/file.py

Usage

OpenClaw agent calls:
const result = await tools.grok_swarm({
prompt: Refactor the auth module,
mode: refactor,
files: [src/auth/*.ts],
write_files: true,
output_dir: ./grok-output/
});

Result: Orchestrator receives compact summary, not 350K token flood.

Closes

Fixes #2

Summary by CodeRabbit

  • New Features

    • Added file writing capability allowing annotated code blocks to be automatically extracted and saved to disk
    • Added write_files toggle (default false) and output_dir configuration option (default ./grok-output/)
    • Path validation prevents unsafe file writes
  • Documentation

    • Simplified API documentation and updated troubleshooting guidance

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 19, 2026

Warning

Rate limit exceeded

@KHAEntertainment has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 11 minutes and 52 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ac6f3dfc-f480-4337-8781-fcfd35f2b23e

📥 Commits

Reviewing files that changed from the base of the PR and between 30f00ea and 10d7318.

📒 Files selected for processing (5)
  • README.md
  • src/bridge/grok_bridge.py
  • src/bridge/index.js
  • src/plugin/index.ts
  • src/plugin/openclaw.plugin.json

Walkthrough

This PR implements file-writing capabilities for the Grok Swarm plugin, enabling the model to extract and persist annotated code blocks directly to disk. The feature spans the documentation, Python bridge, Node.js CLI wrapper, TypeScript plugin layer, and configuration schema, adding optional write_files and output_dir parameters throughout with path validation to prevent unsafe writes.

Changes

Cohort / File(s) Summary
Documentation
README.md
Removed introductory positioning content and replaced with condensed "File Writing" section. Updated API table with new write_files (default false) and output_dir (default ./grok-output/) parameters. Revised troubleshooting guidance for API key resolution to prioritize environment variables over auth profiles.
Backend Implementation
src/bridge/grok_bridge.py
Added response post-processing to parse annotated code blocks (fenced blocks with lang:path/... headers or // FILE: / # FILE: markers), validate target paths against output directory bounds, and write content to disk. Introduced _safe_dest() and parse_and_write_files() functions with path traversal checks. Added --write-files and --output-dir CLI flags.
CLI & Plugin Layer
src/bridge/index.js, src/plugin/index.ts
Added --write-files and --output-dir options to argument parsing and bridge invocation. Extended GrokSwarmSchema with optional write_files and output_dir parameters. Plugin now conditionally passes flags to Python bridge based on parameter values and fallback to configuration defaults.
Configuration
src/plugin/openclaw.plugin.json
Added defaultOutputDir string property to plugin configuration schema (defaults to ./grok-output/).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Plugin as Grok Plugin
    participant Bridge as Python Bridge
    participant Model as LLM Model
    participant FS as File System

    User->>Plugin: Call with write_files=true
    Plugin->>Bridge: Invoke with --write-files flag
    Bridge->>Model: Send prompt + context
    Model->>Bridge: Return response with annotated code blocks
    Bridge->>Bridge: Parse response for lang:path or FILE: markers
    
    rect rgba(100, 150, 200, 0.5)
        Bridge->>Bridge: Validate each path (no traversal, within bounds)
        Bridge->>FS: Create parent directories
        Bridge->>FS: Write UTF-8 content to validated paths
    end
    
    Bridge->>Bridge: Generate file-by-file + aggregate summary
    Bridge->>User: Print summary to stderr
    
    Note over Bridge,User: If write_files=false, full response prints to stdout
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • PR #1 — Overlapping changes to src/bridge/grok_bridge.py and plugin/CLI with identical parameter additions (write_files, output_dir), suggesting parallel or follow-up work on file-writing functionality.

Poem

📝 Code blocks flee from AI's constraints,
Now writing straight to disk they wait—
No more walls of tokens wasted,
Just annotated files, cleanly pasted. 🚀
Output dirs keep safe the way,
while summaries flow, lean and light.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title "Implement file writing for OpenClaw plugin" directly and clearly summarizes the main change—adding file writing capability to the plugin, which is the primary objective.
Linked Issues check ✅ Passed The PR implements the short-term recommendation from issue #2: adding file writing capability to the Grok plugin with --write-files and --output-dir support, including safe path validation and compact summary responses.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing file writing functionality across the Python bridge, JavaScript wrapper, TypeScript plugin schema, configuration, and documentation—no unrelated modifications detected.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude-plugin-v2
📝 Coding Plan
  • Generate coding plan for human review comments

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

❤️ Share

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

Explains the priority order: env vars > local config > OpenClaw profiles.
Adds warning that env vars override config files.
Includes example of how to unset env var to use config file.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds file-writing capability to the Grok Swarm OpenClaw plugin so Grok can emit annotated code blocks that get written to disk, returning a compact summary instead of a huge response.

Changes:

  • Added write_files / output_dir parameters to the OpenClaw tool schema and forwarded them through the TS plugin to the Python bridge.
  • Extended the Node bridge wrapper to accept/pass through --write-files and --output-dir.
  • Implemented response parsing + disk writes in grok_bridge.py, plus README/docs updates and plugin config for a default output directory.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/bridge/grok_bridge.py Implements --write-files / --output-dir and the core parsing + write-to-disk behavior.
src/bridge/index.js Adds CLI arg parsing and forwards file-writing options to Python.
src/plugin/index.ts Extends tool schema and forwards params; supports defaultOutputDir config fallback.
src/plugin/openclaw.plugin.json Adds defaultOutputDir to plugin config schema.
README.md Documents new file writing feature and updates usage/troubleshooting text.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/bridge/grok_bridge.py Outdated
Comment thread src/bridge/grok_bridge.py Outdated
Comment thread src/bridge/grok_bridge.py Outdated
Comment thread README.md Outdated
Comment thread README.md
Comment thread src/bridge/grok_bridge.py Outdated
Comment thread src/bridge/grok_bridge.py Outdated
@KHAEntertainment
Copy link
Copy Markdown
Owner Author

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 19, 2026

@KHAEntertainment I've opened a new pull request, #6, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 2 commits March 19, 2026 21:05
Co-authored-by: KHAEntertainment <43256680+KHAEntertainment@users.noreply.github.com>
Fix security, correctness, and docs issues in file-writing feature
@KHAEntertainment
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 19, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
src/bridge/grok_bridge.py (2)

190-204: Splitting on triple backticks is clever but has a subtle gotcha.

Using re.split(r'```', response_text) splits the response into alternating text/code segments. Odd-indexed parts are code block contents. However, the loop iterates over all parts without checking indices, so it might accidentally try to parse non-code segments (explanation text) if they happen to start with something that looks like lang:path or contain // FILE:.

In practice, this is unlikely to cause real issues since explanation text rarely starts with typescript:src/..., but it's a potential edge case worth a quick note.

🔧 Safer iteration over only code block contents
     # Split into code blocks by ``` fences
     parts = re.split(r'```', response_text)
     
-    for part in parts:
+    # Odd indices are inside fenced blocks, even indices are outside
+    for i, part in enumerate(parts):
+        if i % 2 == 0:
+            continue  # Skip non-code content
+        
         # Check for lang:path at start (language tag contains the path)
         lang_match = lang_path_pattern.match(part)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bridge/grok_bridge.py` around lines 190 - 204, The current split using
parts = re.split(r'```', response_text) then iterating over every part can
accidentally treat non-code text as code; update the loop to only process fenced
code contents (the odd-indexed entries) by iterating with enumerate and skipping
even indices (or replace the split approach with a regex that directly captures
fenced blocks), then continue using lang_path_pattern, file_marker_pattern and
_write_file as before to write detected files; ensure you only call _write_file
for parts that are bona fide code block contents.

135-152: Path validation looks solid, but consider chaining the exception for better debugging.

The _safe_dest function does a good job preventing path traversal attacks — it rejects absolute paths, .. components, and verifies the resolved path stays within the output directory (a nice belt-and-suspenders approach).

However, per the static analysis hint, when re-raising inside an except clause, it's best practice to chain exceptions using raise ... from exc so the original traceback context is preserved.

🔧 Proposed fix for exception chaining
     try:
         dest.relative_to(resolved_root)
     except ValueError:
-        raise ValueError(f"Path escapes output directory: {file_path!r}")
+        raise ValueError(f"Path escapes output directory: {file_path!r}") from None
     return dest
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bridge/grok_bridge.py` around lines 135 - 152, The except block in
_safe_dest currently re-raises a ValueError without chaining, losing original
traceback; update the exception handling in the try/except that checks
dest.relative_to(resolved_root) to re-raise the new ValueError using exception
chaining (i.e., raise ValueError(f"Path escapes output directory:
{file_path!r}") from exc) so the original exception context is preserved when
relative_to fails; locate this in the _safe_dest function where
dest.relative_to(resolved_root) is called and modify the except clause
accordingly.
src/bridge/index.js (1)

141-147: The default-skip optimization is safe but could be clearer.

Line 145 skips passing --output-dir when it matches the hardcoded default './grok-output/'. This works because the Python bridge has the same default (confirmed in the context snippet). However, this creates a hidden coupling — if someone changes the Python default without updating this file, behavior diverges silently.

For CLI-only usage this is fine, and the context snippets confirm that src/plugin/index.ts bypasses this wrapper entirely when spawning Python directly. So this code path is really just for manual CLI invocations.

Consider adding a brief comment to document the coupling:

📝 Add clarifying comment
   if (opts.writeFiles) {
     pyArgs.push('--write-files');
   }

+  // Only pass --output-dir if non-default (Python bridge defaults to same value)
   if (opts.outputDir && opts.outputDir !== './grok-output/') {
     pyArgs.push('--output-dir', opts.outputDir);
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bridge/index.js` around lines 141 - 147, The code currently omits pushing
'--output-dir' when opts.outputDir equals the hardcoded default
'./grok-output/', which creates a hidden coupling with the Python bridge
default; add a short inline comment near the conditional referencing
opts.outputDir and pyArgs that explains this intentional optimization and its
dependency on the Python-side default (mentioning that CLI invocations bypass
this wrapper via src/plugin/index.ts), so future maintainers know why the check
exists and to update both sides if the default changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/bridge/grok_bridge.py`:
- Around line 190-204: The current split using parts = re.split(r'```',
response_text) then iterating over every part can accidentally treat non-code
text as code; update the loop to only process fenced code contents (the
odd-indexed entries) by iterating with enumerate and skipping even indices (or
replace the split approach with a regex that directly captures fenced blocks),
then continue using lang_path_pattern, file_marker_pattern and _write_file as
before to write detected files; ensure you only call _write_file for parts that
are bona fide code block contents.
- Around line 135-152: The except block in _safe_dest currently re-raises a
ValueError without chaining, losing original traceback; update the exception
handling in the try/except that checks dest.relative_to(resolved_root) to
re-raise the new ValueError using exception chaining (i.e., raise
ValueError(f"Path escapes output directory: {file_path!r}") from exc) so the
original exception context is preserved when relative_to fails; locate this in
the _safe_dest function where dest.relative_to(resolved_root) is called and
modify the except clause accordingly.

In `@src/bridge/index.js`:
- Around line 141-147: The code currently omits pushing '--output-dir' when
opts.outputDir equals the hardcoded default './grok-output/', which creates a
hidden coupling with the Python bridge default; add a short inline comment near
the conditional referencing opts.outputDir and pyArgs that explains this
intentional optimization and its dependency on the Python-side default
(mentioning that CLI invocations bypass this wrapper via src/plugin/index.ts),
so future maintainers know why the check exists and to update both sides if the
default changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 51d77e43-3840-445f-8af5-b07174cc1415

📥 Commits

Reviewing files that changed from the base of the PR and between 1ab5f5d and 30f00ea.

📒 Files selected for processing (5)
  • README.md
  • src/bridge/grok_bridge.py
  • src/bridge/index.js
  • src/plugin/index.ts
  • src/plugin/openclaw.plugin.json

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 19, 2026

Merge conflicts resolved successfully!

Resolved 1 conflict file(s). Commit: a2b673b2c5e56e15616237daedd62049117b70b4 pushed to claude-plugin-v2.

5 file operation(s)
  • README.md (update)
  • src/bridge/grok_bridge.py (update)
  • src/bridge/index.js (update)
  • src/plugin/index.ts (update)
  • src/plugin/openclaw.plugin.json (update)
View agent analysis
I'll start by inspecting the git state and examining the conflict in README.md.

Now let me examine what each branch has for this section:

Now I have a clear picture of the conflict. Let me analyze it:

**The conflict is in the Features section:**
- **HEAD (master)**: Has a concise bullet-point Features list (including the new `write_files` feature bullet) followed by the "File Writing" section
- **MERGE_HEAD (claude-plugin-v2)**: Has a lengthy narrative "Enter Grok 4.20..." section followed by old "File Writing Capabilities", "Known Limitations", and "What It Does" sections — all of which were superseded by the condensed content that master has

The rest of the file (after the conflict hunk) in `MERGE_HEAD` also has a **second conflict in the Troubleshooting section** (the API key section). Looking at the current file content, I can see that conflict at lines 236-258.

Additionally, the current working file has a **duplicate "## File Writing" section** (lines 24-60 and 63-103) — this appears to be an artifact of the merge state. The HEAD version has the indented-code-block style (lines 24-60), and MERGE_HEAD has the markdown-fenced style (lines 63-103). Both are equivalent content; HEAD's version is cleaner.

The resolution strategy:
1. **Features section**: Use HEAD's concise bullet list — it's the evolved, cleaner version that supersedes the old narrative
2. **File Writing section**: Keep only one copy (HEAD's indented style is cleaner)
3. **Troubleshooting/API Key section**: Merge both sides — HEAD has more complete auth profile paths + cleaner wording; MERGE_HEAD adds `unset OPENROUTER_API_KEY` tip and mentions `XAI_API_KEY`. The best resolution combines HEAD's comprehensive profile list with MERGE_HEAD's useful `unset` tip

Let me verify the final state:

`git ls-files -u` is empty (no unmerged files) and `README.md` shows `M` (staged, not `UU`). The conflict is fully resolved.

Let me do a quick sanity check on the resolved file:

No conflict markers remain. Here's the resolution summary:

## Resolution

**Conflict location:** `README.md` — two conflicting hunks

### 1. Features section
- **HEAD (master):** Concise 6-bullet feature list (the evolved, PR-goal version)
- **MERGE_HEAD (claude-plugin-v2):** Lengthy narrative about Grok 4.20 followed by old "File Writing Capabilities", "Known Limitations", and "What It Does" sections
- **Resolution:** Kept HEAD's concise bullet list. The verbose narrative sections were superseded by the cleaner format and were not part of the PR's intent.

### 2. Duplicate File Writing section
- The working file had two identical `## File Writing` sections — one with indented code blocks (HEAD's style) and one with markdown-fenced blocks (MERGE_HEAD's style)
- **Resolution:** Kept only the first (HEAD's indented style), removed the duplicate.

### 3. Troubleshooting / API Key section
- **HEAD:** `OPENROUTER_API_KEY` or `OPENCLAW_OPENROUTER_DEFAULT_KEY` → comprehensive 4-path auth profile list
- **MERGE_HEAD:** `OPENROUTER_API_KEY` or `XAI_API_KEY` → local config file → single auth profile path + `unset` example
- **Resolution:** Intelligently merged both sides: kept HEAD's env var names and comprehensive 4-path profile list, added MERGE_HEAD's "Local config file" as step 2, and included the useful `unset OPENROUTER_API_KEY` tip from MERGE_HEAD.

@KHAEntertainment
Copy link
Copy Markdown
Owner Author

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 19, 2026

@KHAEntertainment I've opened a new pull request, #7, to work on those changes. Once the pull request is ready, I'll request review from you.

coderabbitai bot and others added 2 commits March 19, 2026 21:23
Resolved conflicts in:
- README.md (content)

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
Fix byte counting, no-files-found output, and stdout/stderr mixing in grok_bridge.py
@KHAEntertainment KHAEntertainment merged commit 3caaf5c into master Mar 19, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature: File writing and code execution for Grok Swarm plugin

3 participants