---
name: agent-ops
description: Precision rules for AI agents operating in this repo with read/bash/edit/write/remote tools — bounded reads, safe searches, exact edits, remote cwd/memory discipline, timeouts and the verify loop. Use before any multi-step task and when output is truncated, edits fail to match, remote commands run in the wrong directory, or verification is skipped.
---

# Agent Operations

This repo is large and tool output is bounded. Every imprecise call costs a retry. Default to narrow, bounded operations and verify each step.

References: tool schemas in `mcp/tools.php` (read/write/bash/bash_sub/glob/grep/database_query/str_replace_editor), harness prompt in `system/mcp.php` (`MCP::systemPrompt()`), testing and CI in `docs/developer/testing.md` + `.github/workflows/ci.yml`, project rules in `AGENTS.md`.

## Workflow

1. Locate with `glob`/`grep` before reading; read only the needed `offset/limit` window.
2. Change with `edit` (exact unique `oldText`); reserve `write` for new files or full rewrites.
3. Verify the same way every time: `php -l` for PHP, `node --check` for JS, focused harness for logic, relevant suite for models.

## Read and search precisely

- `read` truncates (~2000 lines / 50KB): always pass `offset/limit` and continue in chunks instead of re-reading wholesale.
- Prefer `glob` over `find` for file discovery (`plugins/*/plugin.php`, `**/*.tpl`, max 500 paths, sorted).
- Prefer `grep` over `cat | grep`: set `path`, `include` (`*.php`), `maxResults`, `ignoreCase` only when needed; `SKIP_DIRS` (`.git`, `node_modules`) is automatic.
- `database_query` is read-only by default (`SELECT/SHOW/DESCRIBE/EXPLAIN/WITH`); writes need `mcp.tools.db_write`. SELECTs without LIMIT get one appended (max 1000 rows) — use `?` placeholders with `params`, never interpolate values.

## Bash safely

- Output is capped (~256KB): pipe through `tail`, `sed -n`, `rg --max-count` or `--head` instead of bare `cat`/`find`.
- Always set `timeout` (1–120s, default 30); use `cwd` inside the site root for build tools (`npx gulp fileinclude`, `npm run build`).
- `bash_sub` (pure-PHP bashbox) is the fallback when native shell functions are disabled — same flags, no system calls.
- Destructive commands (`rm`, `mv`, mass `chmod`) need an explicit user request; prefer `glob` previews first.

## Edit without misses

- Each `edits[].oldText` must match a **unique, non-overlapping** region of the original file — matching runs against the original, not incrementally.
- Merge nearby changes into one edit; keep `oldText` minimal but unique; never pad with large unchanged regions.
- One `edit` call can carry multiple disjoint `edits[]` — use that instead of sequential edits to the same file.
- `write` creates parent dirs and overwrites whole files — never use it to patch a file `edit` could handle.

## Remote discipline

- `remote exec` does **not** persist `cd`: pass `cwd` per command or set it once with `remote chdir` — never fake persistence with `cd &&` prefixes.
- Always set `timeout` on `remote exec`; keep output narrow (`tail`, `sed`, `rg --max-count`) — never `cat` large logs or list whole trees.
- Server memory is JSON managed via `remote memory` to locate the file, then `read/edit/write` on that exact local path. Delete an entry only on explicit user request: read first, remove only that object id, ask when ambiguous.
- `note`/`forward`/`disconnect`: annotate endpoints, forward ports only as configured, `disconnect` when returning local on request.

## Verify loop (matches CI)

1. `php -l` every touched PHP file; `node --check` for JS.
2. Model changes: `DB_ENGINE=auto` via `tests/support/TestDb.php` (MySQL when reachable, else throwaway SQLite); never touch existing databases.
3. CI runs `lint` (`php -l` all tracked files), matrix tests (PHP 8.3/8.5 × MySQL/SQLite), non-blocking `phpstan` — no live DB server here, so no live runtime tests.

## Pitfalls

- Re-reading whole files after truncation instead of paging with `offset/limit`.
- Overlapping `edits[].oldText` entries in one call — the whole call fails.
- Running builds in the wrong `cwd` (theme builds run **inside** the theme folder; admin gulp runs in `public/admin/default`).
- Treating `database_query` as a migration tool — it is a query tool; schema changes go through SqlP/install SQL (see `skills/sqlp/SKILL.md`).
