# Tool Execution Reference

`goclaw tools exec` calls registered tools directly from the CLI **without using an LLM**.

```bash
goclaw tools list                                   # every registered tool, with its description
goclaw tools exec <tool_name> [key=value ...]
goclaw tools bench <tool_name> [key=value ...] --runs=N
```

The arguments are the ones the tool's definition declares, the same ones a model sends in a tool call. `goclaw tools list` names every tool; this page shows working calls for the common ones.

## Prerequisites

CLI tool execution automatically loads the following runtime pieces:

| Component | Description |
|-----------|---------|
| `config.yaml` | Tool configuration: API keys, datasources, shell and HTTP allow lists. The global settings apply; no agent is selected, so an agent's own `tools:` overrides do not |
| Database | Memory, SOPs, cron jobs, metrics and other local state (`gc_state.sqlite`, or the configured `database:`) |
| Workspace | `<state dir>/workspace` (`~/.goclaw/workspace` by default), where file tools read and write |
| Runtime context | `channel=cli`, `role=admin`, session `cli-offline-test`, timeout 300s per call (10s per run for `bench`) |

Some tools require additional configuration:

```yaml
# config.yaml - configuration required by selected tools
tools:
  shell:
    allow: ["ls", "git *", "go build *"]  # commands shell_exec may run; empty = shell disabled
  http:
    allow: ["gitlab.example.com", "api.example.com"]  # hosts any HTTP-calling tool may reach
  git:
    allow_write: true                     # needed by auto_commit and git write commands
  gitlab:
    url: "https://gitlab.example.com"
    token: "${env:GITLAB_TOKEN}"

datasources:
  reports-db:
    driver: postgres
    dsn: "${env:REPORTS_DB_DSN}"
```

`exec` does not open the secret vault. A `${secret:NAME}` reference in `config.yaml` reaches the tool as that literal text, so a credential kept in the vault fails to authenticate; `${env:VAR}` and `${file:/path}` references are expanded. The `secret_*` tools answer `secret store not initialized`; manage the vault with `goclaw secret list|get|set|delete` instead.

## Rules for every call

**How values are read.** Each argument is `key=value`, split at the first `=`:

| Value | Becomes |
|-------|---------|
| `10`, `2.5` | a number (float64, as in a model's tool call), so `limit=10` works |
| `true`, `false` | a boolean |
| `{...}` or `[...]` that is valid JSON | an object or array |
| `'...'` or `"..."` | a string, with those quotes removed, whatever is inside |
| anything else | a string |

A parameter the tool declares a string is always the text given, whatever it looks like: `mongo_query filter={"status":"open"}` and `gitlab project=12345` reach the tool as text. The table applies to the other parameters.

**Quoting.** The shell removes one level of quotes before goclaw sees the value, so:

- A parameter the tool does not declare a string is typed by the table: to keep a number-like value a string there, quote it twice: `"id='12345'"`. Written as `id='12345'`, it arrives as `id=12345` and becomes a number.
- Quote a JSON value as a whole word: `'filter={"k":"v"}'`. Unquoted, the shell drops the inner double quotes, and zsh treats `[ ]` as a glob.
- Tools that take JSON *as a string* (`mongo_query filter`, `json_transform data`, `http_request body`, `sop_save steps`) declare it a string, so it stays one: `'filter={"status":"active"}'`, or from a file: `"steps=$(cat steps.json)"`.
- Quote globs and anything with `*`, `?`, `[`, `!` or spaces: `pattern='*.go'`, `endpoint='/syscheck/000?summary=yes'`.
- A multi-line value goes in single quotes with real line breaks, or comes from a file: `patch="$(cat fix.patch)"`.

The `Args:` line at the top of the output is the JSON the tool received. Check it when a value does not do what you expect.

**Paths.** File tools resolve relative paths inside the workspace and refuse paths outside it (`access denied: path "/tmp/a.txt" is outside workspace ...`). An absolute path works only when it points inside the workspace.

**One call per process.** Each `exec` runs one tool call in a fresh process, which exits when the call returns. What a tool keeps in memory does not carry over to the next `exec`: the page `browser` opened, background processes, plan mode, generated HTML pages and `read_output` refs. What lives in the running gateway is not there either: connected channels, the session store, subagent runs and the SOP executor. The sections below say which tools this affects.

**Network.** Tools that make HTTP requests (`web_fetch`, `web_search`, `http_request`, `browser`, `gitlab`, the observability tools, `notify` to a webhook, `pdf`/`document`/`image` with a URL) go through `tools.http`. Its default policy is deny: a host not on `tools.http.allow` is refused, and so is a private address unless the allow list names it. The exception is an integration's own host: `gitlab`, `sonarqube` and the observability tools may reach the `url` you configured for the instance without an allow entry; `tools.http.deny` still applies.

Admin hooks (`hooks:` in `config.yaml`) run on these calls as on an agent's.

---

## Date & Time

### `datetime`

Actions: `now`, `add`, `diff`, `format`, `parse`, `unix`, `weekday`.

```bash
goclaw tools exec datetime action=now
goclaw tools exec datetime action=now timezone=America/New_York
goclaw tools exec datetime action=format date=2026-03-27T11:00:00 format='Mon, 02 Jan 2006 15:04'
goclaw tools exec datetime action=format date=2026-03-27T11:00:00Z timezone=Asia/Ulaanbaatar
goclaw tools exec datetime action=diff from=2026-01-01 to=2026-03-27
goclaw tools exec datetime action=add date=2026-03-27 days=3 hours=6
goclaw tools exec datetime action=unix timestamp=1767225600
goclaw tools exec datetime action=weekday date=2026-03-27
```

`format` takes a Go layout (`2006-01-02 15:04:05`). `add` takes `months`, `days`, `hours` and `minutes` (negative to subtract) and starts from now when `date` is omitted.

---

## Math & Text

### `calc`

```bash
goclaw tools exec calc expression='(1234 * 5.67) / 100'
goclaw tools exec calc expression='sqrt(2) + pi'
goclaw tools exec calc expression='2 ** 10'
```

### `text_utils`

Actions: `base64_encode`, `base64_decode`, `url_encode`, `url_decode`, `sha256`, `md5`, `regex_match`, `regex_extract`, `regex_replace`, `word_count`, `char_count`, `line_count`, `json_prettify`, `json_minify`, `uuid_generate`, `upper`, `lower`, `trim`, `reverse`.

```bash
goclaw tools exec text_utils action=upper text=hello
goclaw tools exec text_utils action=word_count text='Hello world foo'
goclaw tools exec text_utils action=sha256 text=hello
goclaw tools exec text_utils action=regex_extract text='Order 1234 shipped, order 5678 pending' pattern='\d{4}'
goclaw tools exec text_utils action=uuid_generate
```

### `regex`

Actions: `find_all`, `find_first`, `replace`, `split`, `test`. Patterns use Go (RE2) syntax.

```bash
goclaw tools exec regex action=find_all pattern='\d{4}' text='Codes: 1234-5678'
goclaw tools exec regex action=replace pattern='(\w+)@example\.com' replacement='$1@example.org' text='alice@example.com, bob@example.com'
goclaw tools exec regex action=test pattern='^v\d+\.\d+\.\d+$' text=v1.4.0
```

### `diff`

Compares two texts (`old_text`/`new_text`) or two workspace files (`old_file`/`new_file`).

```bash
goclaw tools exec diff old_text='hello world' new_text='hello goclaw'
goclaw tools exec diff old_file=docs/a.txt new_file=docs/b.txt
```

---

## File Operations

All paths below are relative to the workspace.

### `file_read` / `read_file_lines` / `file_write`

```bash
goclaw tools exec file_read path=notes/todo.txt
goclaw tools exec read_file_lines path=payments-api/internal/billing/invoice.go start_line=20 end_line=40
goclaw tools exec file_write path=notes/todo.txt content='Hello'
```

### `file_edit`

Replaces one exact, unique string in a file.

```bash
goclaw tools exec file_edit path=notes/todo.txt old_string=Hello new_string='Hello, world'
```

### `file_search`

```bash
goclaw tools exec file_search path=payments-api query=CalculateTotal
goclaw tools exec file_search path=payments-api query='func \w+Total' is_regex=true file_type=go context_lines=1
goclaw tools exec file_search path=payments-api 'queries=["ErrNotFound","MarkPaid"]' include='*.go'
```

### `glob_files`

```bash
goclaw tools exec glob_files pattern='*.go' dir=payments-api
goclaw tools exec glob_files pattern='**/*.md'
```

### `read_many_files`

```bash
goclaw tools exec read_many_files 'paths=["payments-api/go.mod","notes/todo.txt"]'
goclaw tools exec read_many_files pattern='*.go' dir=payments-api max_files=5
```

### `apply_patch`

Takes a unified diff; the file paths come from its `---`/`+++` headers.

```bash
goclaw tools exec apply_patch patch="$(cat fix.patch)"
goclaw tools exec apply_patch patch='--- a/docs/a.txt
+++ b/docs/a.txt
@@ -1 +1 @@
-old line
+new line
'
```

---

## Shell & Process

### `shell_exec` / `shell_exec_multi` (must be allowed by config)

The command runs in the workspace. It must match `tools.shell.allow`, and characters that chain or redirect commands (`; & | $ > < ( ) =` and similar) are refused even when it does.

```bash
goclaw tools exec shell_exec command='ls -la payments-api'
goclaw tools exec shell_exec command='go build ./...'
goclaw tools exec shell_exec_multi 'commands=["git status","git log --oneline -5"]'
```

### `process`

`process` (actions `start`, `list`, `output`, `kill`) keeps its background processes in the memory of the process that started them. From `exec`, `list`, `output` and `kill` never see a process an earlier `exec` started, so use it through an agent.

### `clipboard`

```bash
goclaw tools exec clipboard action=read
goclaw tools exec clipboard action=write text='Copied from goclaw'
```

---

## Git

### `git`

Runs in the workspace, so the workspace must be a git repository. `args` is the git command line. Read commands always work; writes (`add`, `commit`, `push`, ...) need `tools.git.allow_write: true`. `push --force`, `reset --hard`, `clean -fd` and deleting `main`/`master` are refused, as are `-C`, `-c` and `--git-dir`.

```bash
goclaw tools exec git args=status
goclaw tools exec git args='log --oneline -10'
goclaw tools exec git args='diff --stat HEAD~1'
goclaw tools exec git args='branch -a'
```

### `auto_commit`

Needs `tools.git.allow_write: true`. Stages the listed `paths` (otherwise commits what is already staged) and writes a commit message unless you give one.

```bash
goclaw tools exec auto_commit 'paths=["payments-api/internal/billing/invoice.go"]' message='fix: round invoice totals'
goclaw tools exec auto_commit
```

`undo=true` reverts the last auto-commit made in the same process, so it works only within an
agent run, not from a separate `exec`.

---

## GitLab

### `gitlab`

`project` is a path (`group/repo`) or a numeric ID quoted as a string. Lists take `page` (20 per page). `instance` picks one of `tools.gitlabs` (`gitlab/<name>` works too), or `default` for `tools.gitlab`; omit it for `tools.gitlab`, or for the only instance there is. A name that matches no instance is refused with the list of names.

```bash
goclaw tools exec gitlab action=mrs_list project=group/repo
goclaw tools exec gitlab action=mrs_list project=group/repo state=opened page=2
goclaw tools exec gitlab action=mr_get project=group/repo mr_iid=42
goclaw tools exec gitlab action=mr_changes project=group/repo mr_iid=42
goclaw tools exec gitlab action=issues_list project=group/repo labels=bug state=opened
goclaw tools exec gitlab action=issue_get "project='123'" issue_iid=15
goclaw tools exec gitlab action=pipelines_list project=group/repo
goclaw tools exec gitlab action=pipeline_jobs project=group/repo pipeline_id=9001
goclaw tools exec gitlab action=job_log project=group/repo job_id=55012
goclaw tools exec gitlab action=file_get project=group/repo path=README.md ref=main
goclaw tools exec gitlab action=milestones_list project=group/repo
goclaw tools exec gitlab action=mr_label_events project=group/repo mr_iid=42
goclaw tools exec gitlab action=issue_label_events project=group/repo issue_iid=15 instance=staging
```

---

## Database

### `db_query`

Read-only (`SELECT`, `SHOW`, `DESCRIBE`, `EXPLAIN`, `WITH`).

```bash
goclaw tools exec db_query datasource=reports-db query='SELECT count(*) FROM users'
goclaw tools exec db_query datasource=reports-db query='SELECT date, COUNT(*) FROM events GROUP BY date ORDER BY date DESC LIMIT 7'
goclaw tools exec db_query datasource=clickhouse query='SELECT name FROM system.tables LIMIT 10'
```

### `db_write`

Needs `allow_write: true` on the datasource. `rows`, `set` and `where` are JSON (an object or a JSON string both work).

```bash
goclaw tools exec db_write datasource=crm operation=insert table=orders 'rows=[{"customer":"Alice","total":"120.50"}]'
goclaw tools exec db_write datasource=crm operation=update table=orders 'set={"status":"paid"}' 'where={"id":42}' max_rows=1
goclaw tools exec db_write datasource=crm operation=delete table=orders 'where={"id":[41,42]}' dry_run=true
```

### `mongo_query`

`filter` is a JSON string, so force it (see [Rules for every call](#rules-for-every-call)). `limit` defaults to 50, at most 500.

```bash
goclaw tools exec mongo_query datasource=events-db collection=users "filter='{\"active\":true}'" limit=10
goclaw tools exec mongo_query datasource=events-db collection=orders "filter='{\"status\":\"pending\"}'"
```

---

## Web & Network

### `web_search`

Needs `tools.web_search.brave_api_key` (or `serp_api_key`) and `api.search.brave.com` (or `serpapi.com`) on `tools.http.allow`.

```bash
goclaw tools exec web_search query='Go 1.23 release notes'
goclaw tools exec web_search query='output store pattern site:github.com' max_results=10
```

### `web_fetch`

```bash
goclaw tools exec web_fetch url=https://api.github.com/repos/golang/go/releases/latest
goclaw tools exec web_fetch url=https://example.com
```

### `http_request`

`headers` is text, one `Key: Value` per line; `body` is the raw request body.

```bash
goclaw tools exec http_request url=https://api.example.com/v1/items
goclaw tools exec http_request method=POST url=https://api.example.com/v1/items \
  headers='Content-Type: application/json' "body='{\"name\":\"widget\"}'"
goclaw tools exec http_request method=DELETE url=https://api.example.com/v1/items/7 headers='Accept: application/json
X-Request-Id: cli-test'
```

### `browser`

Needs Chrome. Actions: `navigate`, `screenshot`, `content`, `click`, `type`, `eval`, `wait`, `close`. Every action except `navigate` works on the page an earlier call opened, which a new `exec` does not have, so from the CLI only `navigate` is useful:

```bash
goclaw tools exec browser action=navigate url=https://example.com
goclaw tools exec browser action=navigate url=file://report.html   # an HTML file in the workspace
```

---

## Memory

### `memory_search`

```bash
goclaw tools exec memory_search query='deploy process' max_results=5
goclaw tools exec memory_search query='invoice rounding' time_start=2026-09-01 'tags=["billing"]'
```

### `memory_get`

Takes a chunk ID from a `memory_search` result.

```bash
goclaw tools exec memory_get "chunk_id='3f2a9c0e7b1d4a65'"
```

### `memory_consolidate`

```bash
goclaw tools exec memory_consolidate dry_run=true
goclaw tools exec memory_consolidate lookback_days=60
```

`memory_write` files a record under the person who asked, and `exec` acts for no one, so it answers `could not identify user`. Write memory through an agent, the Web UI or the memory API.

---

## Sessions

The session tools work on the running gateway's sessions and subagent runs. From `exec`, `sessions_list` and `sessions_history` answer `session store not available`, and `sessions_spawn` and `sessions_send` answer `subagent registry not initialized`. Runs are recorded in the database, so `session_status` can look one up:

```bash
goclaw tools exec session_status run_id=job-1759887600123456789-1
```

---

## Agents

### `agents_list`

```bash
goclaw tools exec agents_list
```

### `subagents`

Registration actions (`list`, `inspect`, `create`, `update`, `delete`) work from `exec`; `agent_id` is the agent the subagents belong to. `run` and `follow_up` need the gateway (`subagent registry not initialized`); `list_runs` and `status` read the recorded runs.

```bash
goclaw tools exec subagents action=list agent_id=ops
goclaw tools exec subagents action=inspect agent_id=ops name=code-reviewer
goclaw tools exec subagents action=list_runs
```

### `suggest_agent`

```bash
goclaw tools exec suggest_agent task='database performance issue' top_n=3
```

### `context_detect`

```bash
goclaw tools exec context_detect query='invoice discount' dir=payments-api max_files=5
```

---

## Communication

### `message` / `notify` / `discord_mod`

Sending to a channel needs that channel connected, and channels connect only in the running gateway. From `exec`, `message` refuses a cross-channel send from the `cli` session, `notify` to a channel answers `channel "discord" not connected`, and `discord_mod` answers `no Discord session connected`. `notify` can post to a webhook URL from the CLI (the host must be on `tools.http.allow`):

```bash
goclaw tools exec notify channel=webhook target=https://hooks.example.com/goclaw text='DB connection failed'
```

The call shapes, as an agent sends them: `message channel=discord "target='100000000000000102'" text=...` (optionally `file=reports/week-41.pdf`), `notify channel=msteams target=<conversation ID> text=...`, and `discord_mod action=timeout "guild_id='...'" "user_id='...'" duration_minutes=60` (at most 40320; `ban`, `kick`, `add_role`, `remove_role` take `role_id` or `reason`). Discord IDs are longer than a float64 holds exactly, so always pass them as forced strings.

### `email`

Uses the `email.smtp` / `email.imap` settings. Actions: `send`, `read`, `search`, `reply`.

```bash
goclaw tools exec email action=send to=alice@example.com subject='Weekly report' body='See the attached file.' 'attachments=["reports/week-41.pdf"]'
goclaw tools exec email action=read count=10
goclaw tools exec email action=search from=bob@example.com since=2026-09-01
```

---

## Code Analysis

These tools read files in the workspace. `ast_declarations_search`, `ast_context_extractor`, `call_graph` and `complexity_analyzer` take one file; `dead_code_finder`, `symbol_usage` and `code_health_report` take a directory (`dir`, default the workspace root).

### `ast_declarations_search`

```bash
goclaw tools exec ast_declarations_search path=payments-api/internal/billing/invoice.go
```

### `ast_context_extractor`

Shows the declaration that contains a line.

```bash
goclaw tools exec ast_context_extractor path=payments-api/internal/billing/invoice.go line=25
```

### `ast_diff_analyzer`

Compares two versions of code passed as text.

```bash
goclaw tools exec ast_diff_analyzer filename_hint=invoice.go \
  old_content="$(git show HEAD~1:internal/billing/invoice.go)" \
  new_content="$(cat internal/billing/invoice.go)"
```

### `call_graph`

```bash
goclaw tools exec call_graph path=payments-api/internal/billing/invoice.go focus=CalculateTotal depth=2
```

### `complexity_analyzer`

```bash
goclaw tools exec complexity_analyzer path=payments-api/internal/billing/invoice.go threshold=10
```

### `dead_code_finder`

```bash
goclaw tools exec dead_code_finder dir=payments-api
goclaw tools exec dead_code_finder dir=payments-api include_exported=true
```

### `dependency_map`

```bash
goclaw tools exec dependency_map package=payments-api/internal/billing
goclaw tools exec dependency_map package=payments-api/internal/billing format=mermaid depth=1
```

### `symbol_usage`

```bash
goclaw tools exec symbol_usage symbol=CalculateTotal dir=payments-api
goclaw tools exec symbol_usage symbol=CalculateTotal dir=payments-api include_tests=false
```

### `repo_map`

Maps the whole workspace; `query` and `focus_files` weight the ranking.

```bash
goclaw tools exec repo_map query='invoice totals' max_tokens=1024
```

### `code_health_report`

```bash
goclaw tools exec code_health_report dir=payments-api
goclaw tools exec code_health_report dir=payments-api format=detailed
```

---

## Linting & Security

The linters run in the workspace and must be installed; `setup_dev_env` shows which are missing and how to install them.

### `run_code_linter`

```bash
goclaw tools exec run_code_linter linter=golangci-lint path=payments-api
goclaw tools exec run_code_linter linter=ruff path=scripts/analyze.py
goclaw tools exec run_code_linter linter=dart-analyze path=mobile-app/lib
```

### `run_sast_scanner`

```bash
goclaw tools exec run_sast_scanner scanner=gosec path=payments-api
goclaw tools exec run_sast_scanner scanner=bandit path=scripts
```

### `setup_dev_env`

```bash
goclaw tools exec setup_dev_env
goclaw tools exec setup_dev_env 'languages=["go","python"]'
```

---

## Observability

Each instance is configured under `tools.observability`; its own host needs no entry on `tools.http.allow`. `instance` can be omitted when only one is configured.

### `grafana_alerts`

```bash
goclaw tools exec grafana_alerts instance=prod action=alerts
goclaw tools exec grafana_alerts instance=prod action=dashboards
goclaw tools exec grafana_alerts instance=prod action=annotate text='Deploy started' 'tags=["deploy","api"]'
```

### `graylog_query`

`range` is in seconds (default 3600).

```bash
goclaw tools exec graylog_query instance=prod action=search query='source:api-gateway' range=3600 limit=50
goclaw tools exec graylog_query instance=prod action=search_absolute query='level:3' from=2026-03-27T00:00:00Z to=2026-03-27T12:00:00Z
goclaw tools exec graylog_query instance=prod action=terms_stats query='level:3' field=source range=86400
goclaw tools exec graylog_query instance=prod action=streams_list
```

### `uptrace_query`

Start with `action=projects` to find the `project_id`. UQL strings use single quotes, so wrap the query in double quotes.

```bash
goclaw tools exec uptrace_query instance=main action=projects
goclaw tools exec uptrace_query instance=main action=query project_id=1 query='perMin(count()) | p99(_dur_ms) | group by service.name' time_gte=now-1h
goclaw tools exec uptrace_query instance=main action=spans project_id=1 query="service.name = 'api-gateway'" limit=20
goclaw tools exec uptrace_query instance=main action=spans project_id=1 trace_id=4bf92f3577b34da6a3ce929d0e0e4736
goclaw tools exec uptrace_query instance=main action=monitors project_id=1
```

### `wazuh_query`

```bash
goclaw tools exec wazuh_query instance=main endpoint=/agents/summary/status
goclaw tools exec wazuh_query instance=main endpoint='/syscheck/000?summary=yes'
```

### `zabbix_query`

`params` is a JSON object.

```bash
goclaw tools exec zabbix_query instance=prod method=host.get 'params={"output":["hostid","host"]}'
goclaw tools exec zabbix_query instance=prod method=problem.get 'params={"output":"extend","recent":true}'
goclaw tools exec zabbix_query instance=prod method=trigger.get 'params={"output":"extend","filter":{"value":"1"}}'
goclaw tools exec zabbix_query instance=prod method=item.get 'params={"hostids":"10084","output":"extend"}'
```

### `analyze_pcap`

Takes a `.pcap`, `.pcapng` or `.cap` file in the workspace. Needs `tshark`; without it only `summary` works (through `tcpdump`). Perspectives: `summary`, `conversations`, `dns`, `http`, `errors`, `latency`, `payload`.

```bash
goclaw tools exec analyze_pcap file=captures/edge-router.pcap
goclaw tools exec analyze_pcap file=captures/edge-router.pcap perspective=http
goclaw tools exec analyze_pcap file=captures/edge-router.pcap perspective=dns filter='port 53'
goclaw tools exec analyze_pcap file=captures/edge-router.pcap perspective=latency filter='host 192.0.2.10'
```

---

## Data & Documents

### `json_transform`

`data` is the input *as a string*, so force JSON input to stay a string. Actions: `jq`, `format`, `minify`, `csv_to_json`, `json_to_csv`, `yaml_to_json`, `json_to_yaml`.

```bash
goclaw tools exec json_transform action=jq "data='{\"a\":{\"b\":42}}'" query=.a.b
goclaw tools exec json_transform action=format "data='$(cat response.json)'"
goclaw tools exec json_transform action=json_to_csv "data='[{\"name\":\"Alice\",\"age\":30},{\"name\":\"Bob\",\"age\":25}]'"
goclaw tools exec json_transform action=yaml_to_json data='name: Alice
age: 30'
```

### `spreadsheet`

Actions: `read`, `sheets`, `read_csv`, `create`. `create` writes `.xlsx` or `.csv` from `headers` and `rows`; the directory of `output_path` must already exist.

```bash
goclaw tools exec spreadsheet action=create output_path=team.xlsx 'headers=["name","role"]' 'rows=[["Alice","ops"],["Bob","dev"]]'
goclaw tools exec spreadsheet action=sheets path=team.xlsx
goclaw tools exec spreadsheet action=read path=team.xlsx sheet=Sheet1 range=A1:B10
goclaw tools exec spreadsheet action=read_csv path=exports/orders.csv
```

`data_ref` (a ref from an agent run's large output) is not available from the CLI; see [Large Output Navigation](#large-output-navigation).

### `diagram_render`

Renders Mermaid (default) or raw HTML (`format=html`) to a PNG with headless Chrome, saved in `<state dir>/canvas/`.

```bash
goclaw tools exec diagram_render filename=flow.png content='graph TD
  Request --> Gateway
  Gateway --> Agent'
goclaw tools exec diagram_render format=html content='<h1>Weekly status</h1>' filename=status.png width=800 height=200
```

### `document`

Extracts text from `.docx` and `.pptx` files (a workspace path or a URL).

```bash
goclaw tools exec document path=specs/payments-spec.docx
goclaw tools exec document path=slides/quarterly-review.pptx
```

### `pdf`

```bash
goclaw tools exec pdf path=reports/week-41.pdf
goclaw tools exec pdf path=scans/contract.pdf use_ocr=true
```

`use_ocr` uses Gemini Vision, as `image` does.

### `image`

Analyzes an image with Gemini Vision (needs a Gemini API key).

```bash
goclaw tools exec image path=canvas/flow.png
goclaw tools exec image path=screenshots/dashboard.png question='What is the error rate on the main chart?'
```

---

## Report Generation

### `generate_pdf`

Needs Chrome. `action` is `weekly_report` or `custom`; `sections` is an array of `{type, heading, content}` with `type` one of `text`, `table` (CSV), `bar`, `pie` (CSV of label,value). The file goes to `reports/` in the workspace unless `output_path` says otherwise.

```bash
goclaw tools exec generate_pdf action=custom title='Monthly report' 'sections=[{"type":"text","heading":"Summary","content":"Deploys went out on time."},{"type":"table","heading":"Incidents","content":"service,count\napi-gateway,2\ncore-bank,0"}]'
goclaw tools exec generate_pdf action=weekly_report title='Week 41' output_path=reports/week-41.pdf 'sections=[{"type":"bar","heading":"Tickets closed","content":"Mon,4\nTue,7\nWed,5"}]'
```

### `generate_html`

`generate_html` keeps its pages in the memory of the process that serves them. A page created from `exec` disappears when the command exits, so create pages through an agent.

---

## Large Output Navigation

### `read_output`

The agent loops store a large tool result and hand the model a `[LARGE OUTPUT: ... | ref:<id>]` preview, which `read_output` (and `spreadsheet data_ref=`) reads. `exec` prints a tool's whole result and stores nothing, and the store lives in the gateway process, so a ref from an agent run cannot be read from the CLI.

---

## Secrets

`exec` does not open the vault, so `secret_get`, `secret_set`, `secret_delete` and `secret_list` answer `secret store not initialized`. Use the `goclaw secret` command:

```bash
goclaw secret list
goclaw secret get GITLAB_TOKEN
goclaw secret set MY_API_KEY sk-xxx --category api_key
goclaw secret delete OLD_KEY
```

---

## SOP (Standard Operating Procedures)

SOPs are addressed by `id`. `steps` is a JSON array passed as a string; keep it in a file. Each step needs `id`, `name`, `intent` (at least 20 characters), `instruction` (at least 80) and `tools`.

```bash
goclaw tools exec sop_list
goclaw tools exec sop_get id=open-tickets
goclaw tools exec sop_history id=open-tickets limit=5
goclaw tools exec sop_versions id=open-tickets
goclaw tools exec sop_enable id=open-tickets enabled=false
goclaw tools exec sop_save id=open-tickets name='Open tickets' \
  purpose='Report how many support tickets are open, by priority.' "steps='$(cat steps.json)'"
goclaw tools exec sop_delete id=open-tickets
```

With `steps.json`:

```json
[{"id":"s1","name":"Count open tickets","intent":"Count the support tickets that are still open today","instruction":"Run a SELECT on the tickets table of the reports-db datasource that counts rows with status open, grouped by priority. Return the counts as a compact JSON object.","tools":["db_query"],"output_format":"JSON object {priority: count}","success_check":"json"}]
```

`sop_run` needs the gateway's SOP executor: from `exec` it answers `SOP executor not initialized`. Run a SOP from the Web UI, the API or a chat.

---

## Task Tracker

Task IDs are strings like `T001`.

```bash
goclaw tools exec tracker_create_task title='Fix DB connection' priority=high
goclaw tools exec tracker_list_tasks
goclaw tools exec tracker_list_tasks status=todo
goclaw tools exec tracker_get_task id=T001
goclaw tools exec tracker_update_task id=T001 status=done
goclaw tools exec tracker_add_dependency task_id=T002 depends_on=T001
goclaw tools exec tracker_visualize
```

---

## Metrics Store

```bash
goclaw tools exec metrics_store action=record source=gitlab entity_type=mr entity_id='group/repo#42' \
  'metrics={"cycle_time_h":18.5,"review_rounds":2}' 'tags={"team":"payments"}'
goclaw tools exec metrics_store action=query filter_source=gitlab filter_metric=cycle_time_h date_from=7d
goclaw tools exec metrics_store action=trend filter_metric=cycle_time_h weeks=4
goclaw tools exec metrics_store action=annotate source=gitlab entity_id='group/repo#42' notes='Release 1.4.0 deployed'
goclaw tools exec metrics_store action=purge date_from=90d filter_source=custom
```

`annotate` adds notes to the rows already recorded for that source and entity. `purge` deletes rows older than `date_from`.

---

## Cron

Schedules have six fields, seconds first (`0 0 9 * * 1-5` is 09:00 on weekdays), or `@every 30s`. A new job runs a SOP (`sop_id`) or a built-in `notify ...` command; shell commands are refused.

```bash
goclaw tools exec cron action=list
goclaw tools exec cron action=create schedule='0 0 9 * * 1-5' sop_id=open-tickets
goclaw tools exec cron action=create schedule='0 30 8 * * *' command='notify channel=discord target=100000000000000102 text=Standup in 30 minutes'
goclaw tools exec cron action=history id=cron-1
goclaw tools exec cron action=delete id=cron-1
```

A job created or deleted from `exec` is written to the database, and a running gateway picks the change up within 30 seconds. Only the gateway runs jobs: `exec`, and `goclaw chat`, run none themselves.

---

## Planning Mode

```bash
goclaw tools exec write_todos title='Release 1.4' \
  'todos=[{"content":"Fix bug","status":"completed"},{"content":"Write tests","status":"in_progress","priority":"high"},{"content":"Deploy","status":"not_started"}]'
```

`enter_plan_mode` (`reason=...`) and `exit_plan_mode` (`plan=...`) switch a flag held in memory. It lasts only for the `exec` that set it, so they do nothing useful from the CLI.

---

## MCP (Model Context Protocol)

`server` is a name from `mcp.servers` in `config.yaml` (or an MCP URL); `arguments` is a JSON object.

```bash
goclaw tools exec mcp action=list_servers
goclaw tools exec mcp action=list_tools server=my_mcp
goclaw tools exec mcp action=call_tool server=my_mcp tool=search 'arguments={"query":"hello"}'
goclaw tools exec mcp action=list_resources server=my_mcp
goclaw tools exec mcp action=read_resource server=my_mcp uri='resource://docs/readme'
```

---

## Voice

### `voice_input`

Transcribes an audio file (wav, mp3, m4a, webm, ogg, flac and similar, up to 25 MB) with the configured speech-to-text provider. `audio_path` is read inside the workspace, like `file_read`: a path outside it is refused.

```bash
goclaw tools exec voice_input audio_path=recordings/standup.m4a
goclaw tools exec voice_input audio_path=recordings/standup.m4a language=mn
```

---

## Archive

### `archive_search`

Searches the conversation archives written when session history is summarized. With no `query`, it lists them.

```bash
goclaw tools exec archive_search
goclaw tools exec archive_search query='deploy error' max_results=10
goclaw tools exec archive_search query='Q1 report' date=2026-03-14
```

### `archive_get`

Takes a file name from an `archive_search` result.

```bash
goclaw tools exec archive_get filename=session_discord_123_2026-03-14_2313.md
goclaw tools exec archive_get filename=session_discord_123_2026-03-14_2313.md section=summary
```

---

## Benchmark Examples

`bench` runs the call `--runs` times (default 5), each with a 10-second limit, and prints min, max, average and p95 latency.

```bash
goclaw tools bench datetime action=now --runs=50
goclaw tools bench memory_search query=test --runs=10
goclaw tools bench db_query datasource=reports-db query='SELECT 1' --runs=20
goclaw tools bench web_fetch url=https://example.com --runs=5
```
