Document the new tools, plugins, skills, MCP panel, and item repair

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
Muhammad Zakir Ramadhan
2026-09-05 17:32:32 +07:00
co-authored by Sisyphus
parent 2dc7b91c29
commit 397c4355f3
10 changed files with 273 additions and 26 deletions
+37 -5
View File
@@ -19,7 +19,7 @@ the agent can read. That is a sandbox problem, not a loader problem — see
## Enabling
```json
{ "plugins": ["guard", "time"] }
{ "plugins": ["guard", "secrets", "protect", "time"] }
```
That is also the default when the field is absent, and it lists **builtin** plugins only.
@@ -95,6 +95,34 @@ a `write_file` overwriting something important is an approval question, not a gu
The guard is the last line before a command runs; `ctrl-c` is the one after. A pattern the guard
does not know about is still interruptible by hand — see [tools](tools.md#bash).
### `protect` (default on)
Refuses writes to files whose contents belong to a tool rather than to anyone editing them by
hand. This is a different failure from a secret: the repository looks fine and behaves wrongly,
and the breakage surfaces somewhere else entirely.
| Refused | Why |
|---|---|
| `.git/**` | git's own object store |
| `bun.lock`, `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `Cargo.lock`, `go.sum`, `poetry.lock`, `uv.lock`, `composer.lock`, `Gemfile.lock` | the package manager owns it |
| `node_modules/**` | an installed dependency |
| `vendor/**`, `target/debug/**`, `target/release/**` | vendored or build directory |
| `dist/**`, `build/**`, `out/**`, `.next/**`, `.nuxt/**`, `.svelte-kit/**`, `coverage/**` | generated output |
| `.venv/**`, `.tox/**`, `.mypy_cache/**`, `.ruff_cache/**`, `.turbo/**` | tool caches |
```
refusing to write bun.lock (a lockfile the package manager owns). Regenerate it with the
tool that owns it rather than editing it.
```
The message says what to do instead, which matters: a model told only "no" writes the same
content somewhere else. A lockfile is regenerated by `bun install`; build output is regenerated
by the build.
Both separators match, so `node_modules\react\index.js` is refused on Windows too. Lookalike
names are not: `src/gitignore-parser.ts`, `docs/dist-layout.md`, and `distributed/queue.ts` all
write normally.
### `time` (default on)
Adds `current_time`, returning ISO 8601 plus the local string. Auto-approved; it reads
@@ -106,7 +134,7 @@ Writes `\u0007` to stderr when a turn ends. Off by default — a bell after ever
intrusive, but it is genuinely useful when a turn takes minutes.
```json
{ "plugins": ["guard", "time", "bell"] }
{ "plugins": ["guard", "secrets", "protect", "time", "bell"] }
```
## Writing one
@@ -125,7 +153,8 @@ export const noSecretsPlugin: Plugin = {
'The no-secrets plugin refuses writes to .env and credential files. Ask the user to ' +
'add secrets themselves rather than working around it.',
beforeToolCall: ({ toolName, input }) => {
if (!['write_file', 'edit_file', 'multi_edit', 'apply_patch'].includes(toolName)) return undefined;
const WRITE_TOOLS = ['write_file', 'edit_file', 'multi_edit', 'apply_patch', 'move_file', 'delete_file'];
if (!WRITE_TOOLS.includes(toolName)) return undefined;
const path = String((input as { path?: unknown } | null)?.path ?? '');
if (/(^|\/)\.env|credentials|\.pem$/.test(path)) {
return `refusing to write ${path}; add secrets yourself`;
@@ -137,8 +166,11 @@ export const noSecretsPlugin: Plugin = {
Then add it to `BUILTIN_PLUGINS` and, if it should be on by default, `DEFAULT_ENABLED`.
Note the four tool names. Every write tool has to be listed, and `multi_edit` is easy to miss
— a guard that only checks `write_file` and `edit_file` is bypassed by a batch edit.
Note the six tool names. Every write tool has to be listed, and `multi_edit`, `apply_patch`,
and `move_file` are all easy to miss — a guard that only checks `write_file` and `edit_file` is
bypassed by a batch edit, a patch, or a rename. `apply_patch` and `move_file` also carry their
paths somewhere other than `path`, so a guard reading only that field sees nothing to check.
The builtins share one `writtenPaths` helper for exactly that reason.
Write the `appendix` whenever the plugin can block something. Without it the model hits a
refusal it was never told about and tries to route around it.