JustToThePoint English Website Version
JustToThePoint en español

OpenClaw: A Practical Guide to Running a Local Autonomous AI Agent — Part 4: File Management and the exec Permission Model

With artificial intelligence, we are summoning the demon, Elon Musk

AI won’t replace humans, but those who use AI will replace those who don’t, Garry Kasparov

AI is not a threat; it’s a tool, but what a f**ng tool, Anawim, justothepoint.com

OpenClaw

Hands: File Tools, Obsidian, and Safe Shell Access

In Parts 1 through 3 we gave our OpenClaw agent a body (the Gateway and workspace), a memory (skills, QMD), and senses (Gmail, Calendar, search). But an autonomous agent that can only talk is an advisor. In this fourth installment, we give it hands.

OpenClaw's file tools give the agent direct access to the machine it runs on — no copy-paste required. But 'file management' is really six tools with different risk profiles, and the difference between a useful agent and a dangerous one is knowing which tool to reach for and which permission mode to leave it in.

We begin with a detour through Obsidian: its new official CLI turns your notes vault into a structured, scriptable knowledge base the agent can search, read, and write without ever leaving the terminal. Then we take an honest tour of the file tool surface — read, write, edit, search, and the powerful but dangerous exec — work through a realistic example (installing a zsh function), and finish with the permission model and safety checklist that let you sleep while your agent works.

Obsidian CLI: the official command line, not a third-party wrapper

Obsidian now ships an official CLI that controls the running desktop app from your terminal. This is preferable to third‑party wrappers because it guarantees compatibility, avoids extra dependencies, and lets you script the vault directly.

  1. Enable it. In the Obsidian desktop app: Settings → General → Command line interface. On macOS, registration creates /usr/local/bin/obsidian pointing at the app-bundled CLI; on Linux it copies the binary to ~/.local/bin/obsidian.
  2. Verify: obsidian version, obsidian help.
  3. Obsidian desktop tracks vaults in ~/Library/Application Support/obsidian/obsidian.json. This is the source of truth for which vaults exist and which one is open. The OpenClaw Obsidian skill reads this file rather than guessing paths.
  4. Uses:
# A. Command grammar
# The CLI uses key=value parameters and boolean flags:
obsidian command [name=value ...] [flag]
# format=json gives structured output, which is what you want when an agent is parsing results.
obsidian vault="Notes" search query="meeting notes" format=json

# B. Open and read
# file=name uses Obsidian-style name resolution.
obsidian open file=Agenda.md
# path="Folder/Note.md" is exact vault-relative resolution.
obsidian open path="assets/Todo.md" 
# obsidian read with no argument reads the active file
obsidian read

# C. Search
# matches returns matching lines; format=json returns structured results
obsidian search query="TODO" matches
obsidian search query="TODO" matches format=json

# D. Create, append
obsidian create name="New Note"
obsidian create path="Inbox/Idea.md" content="# Idea"
obsidian append file=Note content="New line"

# E. Move, delete
obsidian move file=Note to=Archive/
obsidian move path="Inbox/Old.md" to="Projects/New.md"
obsidian delete file=Note

OpenClaw File Management: Read, Write, Edit, Search, and Exec

OpenClaw’s file tools give the agent direct access to the machine it runs on — no copy‑paste required. But “file management” is really six tools with different risk profiles, and the difference between a useful agent and a dangerous one is knowing which tool to reach for and which permission mode to leave it in.

This article covers the tool surface, a realistic worked example (adding a zsh function), the exec parameters that matter, and the correct way to put exec behind approval.

OpenClaw File Management: Read, Write, Edit, Search, and Exec — Practically

OpenClaw’s file tools give the agent direct access to the machine it runs on — no copy‑paste required. But “file management” is really six tools with different risk profiles, and the difference between a useful agent and a dangerous one is knowing which tool to reach for and which permission mode to leave it in.

This article covers the tool surface, a realistic worked example (adding a zsh function), the exec parameters that matter, and the correct way to put exec behind approval.

1. The tool surface at a glance

Tool Group What it is for Risk
read group:fs Read file contents (text or images), with offset/limit for large files Low (read-only)
write group:fs Create or overwrite a file; creates parent directories High (overwrites silently)
edit group:fs Exact string replacement in an existing file Medium–high (a wrong match corrupts)
apply_patch group:fs Structured diff-based patching (experimental) Medium
exec group:runtime Run shell commands, foreground or background Highest
process group:runtime Poll, log, kill, clear background exec sessions Medium

2. Reading and writing files

The single most important habit: read first, then edit or write. write overwrites without warning, and edit fails (or corrupts) if the exact string is not present.

# Prompt Example
Read README.md in my Python directory and summarize it.
# Output
Here's a summary of the README.md in ~/macOS/myPython:
Hugo Content Toolkit (v0.17)
A Python toolkit that reviews, enriches, and quality-checks Markdown pages of your Hugo website (justtothepoint) using a local LLM (Ollama) and the live Hugo server. [...]

edit does an exact string replacement, not a regex and not a fuzzy match. If whitespace differs — tabs vs spaces, trailing spaces — the edit fails. That is a safety feature: it will not silently match the wrong occurrence. The practical fix is to copy the exact block from a fresh read, then replace it.

If you do not want the agent touching dotfiles or system paths, set:

{
  # Safety measure: Keep the agent inside the workspace
  "tools": {
    "fs": {
      "workspaceOnly": true
    }
  }
}

This restricts read/write/edit to the workspace directory. It does not restrict exec — which is exactly why the two controls must be considered separately.

3. Search before you edit

Most file tasks start with “find where this is.” exec plus ripgrep is the right tool; read is the wrong one.

# Find files containing a phrase
rg -l 'Talonario Recetas' ~/macOS

# Case-insensitive, with line numbers
rg -in 'talonario recetas' ~/macOS

# Restrict to Markdown, skip .git and node_modules
rg -l -g '*.md' -g '!.git/**' -g '!node_modules/**' 'Talonario Recetas' ~/macOS

Practical notes:

4. Worked example: adding hugo-image-posts to .zsh_functions

The goal: a function that, given an image filename, prints every Hugo post that references it.

hugo-image-posts() {
  local content="/Volumes/MacDatosMaster/justtothepoint/content"
  # A **zsh history modifier** that takes the tail (basename) of a path. 
  # `hugo-image-posts /a/b/hero.png` searches for `hero.png`, not the full path.
  local image="${1:t}"  # Use the filename even if you pass a full path

  if [[ -z "$1" ]]; then
    # Writes to **stderr** (fd 2), so the message is not captured as normal output.
    print -u2 -- "Usage: hugo-image-posts "
    # Distinct exit codes: `2` = usage error, `1` = missing directory.
    return 2
  fi

  if [[ ! -d "$content" ]]; then
    print -u2 -- "Hugo content directory not found: $content"
    return 1
  fi

  # `rg -F`: **Fixed-string** match. The `.` in `hero.png` is literal, not “any character.”
  # `rg -l`: Print **filenames only**, which is what you want for “which posts reference this.”
  # `--sort path`: Deterministic output order
  # `--hidden --no-ignore`: Includes hidden files and ignores `.gitignore`.
  # `-g '*.md'`: Limits to Markdown.
  # `-- "$image"`: The `--` separates options from the pattern, so a filename starting with `-` is not parsed as a flag.
  rg -F -l --sort path --hidden --no-ignore -g '*.md' -- "$image" "$content"
}
Add the following zsh function to `~/.zsh_functions`.

First read the file and inspect its contents. Preserve everything already there. Append the function at the end only if it is not already present; if it is present, update that function without changing unrelated content. Use a targeted patch rather than rewriting the whole file.

After editing, run `zsh -n ~/.zsh_functions` to check the file’s syntax. Provide a comment to explain its functionality.

Function to add:

hugo-image-posts() {
  local content="/Volumes/MacDatosMaster/justtothepoint/content"
  local image="${1:t}"

  if [[ -z "$1" ]]; then
    print -u2 -- "Usage: hugo-image-posts "
    return 2
  fi

  if [[ ! -d "$content" ]]; then
    print -u2 -- "Hugo content directory not found: $content"
    return 1
  fi

  rg -F -l --sort path --hidden --no-ignore -g '*.md' -- "$image" "$content"
}

Then, reload and test:

source ~/.zsh_functions
hugo-image-posts MomSittingThinkingBedroomDog.jpg

Expected output is the list of .md files, exactly as in the example.

5. The exec tool: parameters that matter

exec is not just “run a command.” These parameters change its behaviour:

Parameter Default Practical meaning
command required The shell command.
workdir current directory Set it explicitly when the command depends on a project root.
timeout 1800 s Kills the process on expiry. Long enough for builds; too long for a hung command you forgot about.
yieldMs 10000 ms After 10 s, the command is moved to the background automatically.
background false Background immediately.
pty false Use a pseudo-terminal — needed for TTY-only CLIs, interactive coding agents, and terminal UIs.
host sandbox Where it runs: sandbox, gateway, or node.
security deny (sandbox) / allowlist (gateway + node) deny, allowlist, or full.
ask on-miss off, on-miss, or always — approval prompts for gateway/node.
elevated false Requests elevated mode on the gateway host.

With host=gateway, OpenClaw merges your login-shell PATH into the exec environment, but the daemon itself runs with a minimal PATH — on macOS, /opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin. If a command works in your terminal but not through the agent, the usual cause is that the binary lives somewhere the daemon does not see. Therefore, you must fix the environment (tools.exec.pathPrepend), not the command.

6. The permission model

# Run commands that match the configured allowlist, and request human approval for commands that don’t. 
{
  "tools": {
    "exec": {
      "mode": "ask"
    }
  }
}

Or from the CLI:

openclaw config set tools.exec.mode ask
openclaw approvals get            # verify the effective policy
openclaw gateway restart          # apply

tools.exec.mode is the normalized policy interface. Each mode resolves to an underlying security / ask pair:

Mode security / ask Behaviour Use when
deny deny / off Blocks host exec entirely No host commands should run
allowlist allowlist / off Runs allowlisted commands; silently refuses misses You have a known-safe command set
ask allowlist / on-miss Runs allowlisted commands; prompts a human on a miss Every new command form should be reviewed
auto allowlist / on-miss Same, plus a native automatic reviewer before human approval Coding sessions that need practical but guarded access
full full / off Runs host exec without prompts A trusted host/session only

The docs’ recommended default for coding agents is auto, not ask: it keeps the allowlist and only escalates to a human when the automatic reviewer cannot safely approve.

7. Safety checklist

8. Quick reference

# Read / search
rg -l -g '*.md' -g '!.git/**' 'pattern' ~/macOS
rg -in 'pattern' path/

# Safe edit workflow
# 1) read the target  2) locate a unique anchor  3) edit/apply_patch  4) re-read to confirm

# zsh inventory
zsh -ic 'alias -L'
zsh -ic 'functions'

# exec policy
openclaw config set tools.exec.mode ask
openclaw approvals get
openclaw gateway restart

# Inspect what the agent can actually do
openclaw config get tools.fs
openclaw config get tools.exec

openclaw-feeds

  1. RSS news aggregator. Fetches all current entries from curated feeds across three categories — news, games, and finance. Concurrent fetching, streamed JSON output. No API key needed.
  2. Install the skill openclaw skills install @nesdeq/openclaw-feeds
  3. It requires feedparser.
    # Create a virtual environment for that skill. 
    cd ~/macOS/claude/skills/openclaw-feeds
    python3 -m venv .venv
    # Install feedparser there.
    .venv/bin/python -m pip install --upgrade pip
    .venv/bin/python -m pip install feedparser 
    # Run the script with that environment’s Python:
    .venv/bin/python scripts/feeds.py --category news
    
  4. Update my Daily Briefing skill.
    ### 5. Tech News — latest headlines
    
    Use the `openclaw-feeds` skill to fetch the latest tech news. Run from the skill directory with the venv Python:
    
    ```bash
    ~/macOS/claude/skills/openclaw-feeds/venv/bin/python3 ~/macOS/claude/skills/openclaw-feeds/scripts/feeds.py --category news
    ```
    
    - Parse the JSON output. The first element is metadata; the rest are entries with `title`, `url`, `source`, `date`, `summary`.
    - Select the 5 most interesting or highest-priority headlines.
    - Group by theme if there are clear clusters (e.g. AI, Hardware, Industry, Security).
    - For each: **headline as markdown link** — one-line summary *(source)*.
    - If zero entries or error, say "tech news unavailable" — do not invent headlines.
    
    [...]
    ## Output format
    📰 Tech News
    - **<headline>**(url) — summary *(source)*
    - ...
    

Daily Gospel

  1. Create a directory for your skill, a virtual environment for that skill, and install feedparser.
    SKILL="$HOME/macOS/claude/skills/daily-gospel"
    mkdir -p "$SKILL/scripts"
    python3 -m venv "$SKILL/venv"
    "$SKILL/venv/bin/python3" -m pip install feedparser
    
  2. Create a script for your skill, nvim ~/macOS/claude/skills/daily-gospel/scripts/daily_gospel.py.
    import json
    from html.parser import HTMLParser
    import feedparser
    
    FEED_URL = "https://rss.evangelizo.org/rss/v2/evangelizo_rss-am.xml"
    
    class TextOnly(HTMLParser):
        def __init__(self):
            super().__init__()
            self.parts = []
    
        def handle_data(self, data):
            self.parts.append(data)
    
    
    feed = feedparser.parse(FEED_URL)
    
    if not feed.entries:
        raise SystemExit(f"No entries found in feed. Parser error: {feed.get('bozo_exception', 'unknown')}")
    
    entry = feed.entries[0]
    content = entry.get("content", [])
    raw_text = content[0].get("value", "") if content else entry.get("summary", "")
    
    parser = TextOnly()
    parser.feed(raw_text)
    reading = " ".join(" ".join(parser.parts).split())
    
    result = {
        "title": entry.get("title", ""),
        "date": entry.get("published", entry.get("updated", "")),
        "reading": reading,
        "link": entry.get("link", ""),
    }
    
    print(json.dumps(result, ensure_ascii=False, indent=2))
    
  3. Test it.
    "$HOME/macOS/claude/skills/daily-gospel/venv/bin/python3" \
    "$HOME/macOS/claude/skills/daily-gospel/scripts/daily_gospel.py"
    
  4. Create the skill, nvim ~/macOS/claude/skills/daily-gospel/SKILL.md
    ---
    name: daily-gospel
    description: Fetch the latest daily Gospel reading from the Evangelizo RSS feed.
    ---
    
    When the user asks for the daily Gospel or daily reading, run:
    
    `{baseDir}/venv/bin/python3 {baseDir}/scripts/daily_gospel.py`
    
    Present the title, date, and reading. Include the feed link if useful. If the script reports an error or no entry, report that instead of inventing a reading.
    

Better safe than sorry

I want a skill like ClawHub Finance Skill. It tracks stocks, ETFs, indices, crypto (where available), and FX pairs with caching + provider fallbacks.

  Install the intended ClawHub finance skill. First identify the exact skill name, publisher, and version, and inspect its SKILL.md, scripts, and requirements.txt. Explain what it will install and run, and wait for my approval before making changes. After approval, install the skill, create a .venv inside the skill directory with uv, and install only the listed requirements into that environment. Do not install packages into system Python, use sudo, or add API keys. Run scripts with that venv’s Python. At the end, tell me the installed path, dependencies, and any test results.

Answer:

  📋 ClawHub Finance Skill — Inspection Report
Skill: @anton-roos/finance v1.1.2
Publisher: anton-roos (community, not official)
Security audit: ✅ Safe — no hidden or destructive behavior found
Downloads: 14,255 | Stars: varies
[...]
What I'll do (pending your approval)
Create .venv inside ~/macOS/claude/skills/finance/ using uv
Install only yfinance, pandas, requests into that venv (no system Python, no sudo)
Run a test quote to verify it works
Report installed path, dependencies, and test results

No system changes. No API keys. No sudo.
Approve to proceed?

After approval,

[...]
✅ Finance Skill Installed & Tested
Item	Detail
Skill	@anton-roos/finance v1.1.2
Path	~/macOS/claude/skills/finance/
Venv	.venv/ (Python 3.15, created with uv)
Security	✅ Safe (ClawHub audit)

[...]
How to use
cd ~/macOS/claude/skills/finance

# Quote
.venv/bin/python scripts/market_quote.py AAPL
.venv/bin/python scripts/market_quote.py EURUSD

Using the skill:

/finance compare AAPL,MSFT,GOOGL
Bitcoin donation

JustToThePoint Copyright © 2011 - 2026 Anawim. ALL RIGHTS RESERVED. Bilingual e-books, articles, and videos to help your child and your entire family succeed, develop a healthy lifestyle, and have a lot of fun. Social Issues, Join us.

This website uses cookies to improve your navigation experience.
By continuing, you are consenting to our use of cookies, in accordance with our Cookies Policy and Website Terms and Conditions of use.