Synced from monorepo
Synced from monorepo Changes: - Report invalid MCP server config instead of failing startup - Keep completed terminal output when the gateway connection is lost - Show a duration-only detail view for single-task task output - Don't let a stale registry turn counter hide local sessions - Raise the file-descriptor soft limit on Linux and log effective limits at startup - Stop aborting when HTTP client construction fails - Make session thread and runtime spawn failures recoverable - Fix main-prompt paste parity in the question freeform input - Fire SessionEnd hooks on /exit and headless quit - Embed the deployment-config signing public key - Repaint paste-chip background on inline panel inputs - Security: prevent acceptEdits from auto-approving agent writes into the always-trusted global hook root - Fix stacked "Worked for" markers so parks render as status and turns close with exactly one marker - Parse hooks from config files - Add a remote kill-switch for managed-config signature verification - Security: fix workspace file-reference resolution bypassing workspace filesystem confinement Source-Revision: d02693a856a54f1030695b36b91d276e96b30b23
This commit is contained in:
parent
6e38642082
commit
47348d13ec
138 changed files with 7283 additions and 5796 deletions
|
|
@ -68,9 +68,12 @@ Hooks are discovered from several places (all are merged):
|
|||
| Project | `<project>/.grok/hooks/*.json` | Requires trust | Per-repo automation |
|
||||
| Project | `<project>/.claude/settings.json` (and `settings.local.json`) | Requires trust | Claude compatibility (configurable) |
|
||||
| Project | `<project>/.cursor/hooks.json` | Requires trust | Cursor compatibility (configurable) |
|
||||
| Config | `~/.grok/config.toml` | Always | Your hooks alongside the rest of your config |
|
||||
| Config | `managed_config.toml` (`$GROK_HOME` and `/etc/grok`) | Always | Organization-distributed hooks (server-synced and on-device) |
|
||||
| Config | `requirements.toml` (user and system) | Always | Organization-distributed hooks in the requirements layer |
|
||||
| Plugin | Bundled inside installed plugins | Per-plugin | Shared team hooks |
|
||||
|
||||
The Claude and Cursor hook sources are scanned by default. To disable scanning for a specific vendor, set `[compat.<vendor>] hooks = false` in `~/.grok/config.toml` or the corresponding environment variable. See [Configuration](05-configuration.md#harness-compatibility) for details.
|
||||
Config-file hooks live in the same TOML your organization already controls; see [Hooks in Config Files](#hooks-in-config-files) for the format. The compatible vendor hook sources are scanned by default. To disable scanning for a specific vendor, set `[compat.<vendor>] hooks = false` in `~/.grok/config.toml` or the corresponding environment variable. See [Configuration](05-configuration.md#harness-compatibility) for details.
|
||||
|
||||
**Trusting a project**: The first time you open a project with hooks, you must trust it before its project hooks will run -- until then they are silently skipped. Grant trust by running `/hooks-trust` (or launching with `--trust`); the decision is recorded in the unified folder-trust store (`~/.grok/trusted_folders.toml`), the same gate that governs repo-local MCP/LSP servers. Global hooks in `~/.grok/hooks/` are always trusted and need no entry. This prevents untrusted repos from running arbitrary code.
|
||||
|
||||
|
|
@ -168,6 +171,47 @@ A matcher keeps its original name too, so `Bash` matches both `Bash` and `run_te
|
|||
|
||||
---
|
||||
|
||||
## Hooks in Config Files
|
||||
|
||||
Hooks can also live directly in your Grok config, so a team can distribute them with the rest of their configuration instead of shipping separate JSON files. The same `hooks` object is read from three TOML files:
|
||||
|
||||
| File | Tier | Who sets it |
|
||||
|------|------|-------------|
|
||||
| `~/.grok/config.toml` | User | You |
|
||||
| `managed_config.toml` (`$GROK_HOME`, `/etc/grok`) | Managed / system | Your organization |
|
||||
| `requirements.toml` (user and system) | Requirements | Your organization |
|
||||
|
||||
The TOML is structurally identical to the JSON hook object, so an existing hook transliterates directly:
|
||||
|
||||
```toml
|
||||
[[hooks.PreToolUse]]
|
||||
matcher = "Bash|Write|Edit"
|
||||
hooks = [
|
||||
{ type = "command", command = "/opt/guard/pretooluse.sh", timeout = 10 },
|
||||
]
|
||||
```
|
||||
|
||||
Each matcher group is a `[[hooks.<Event>]]` entry with an optional `matcher` and an inner `hooks` array of handlers. The handler fields (`type`, `command`, `url`, `timeout`, `env`) and event names are exactly the same as the [JSON format](#the-hook-json-format).
|
||||
|
||||
TOML offers two equivalent notations for the inner handlers, and both parse to the identical structure. The inline-table array shown above is recommended: it reads best for the common single-handler case. The nested array-of-tables form is also accepted:
|
||||
|
||||
```toml
|
||||
[[hooks.PreToolUse]]
|
||||
matcher = "Bash|Write|Edit"
|
||||
[[hooks.PreToolUse.hooks]]
|
||||
type = "command"
|
||||
command = "/opt/guard/pretooluse.sh"
|
||||
timeout = 10
|
||||
```
|
||||
|
||||
Prefer the inline form to avoid repeating the `[[hooks.<Event>.hooks]]` header for each handler.
|
||||
|
||||
- **Additive across layers.** Every layer's hooks run; a lower-priority layer adds hooks but never replaces another layer's block. A hook defined identically in more than one layer is deduplicated, keeping the highest-authority copy.
|
||||
- **Provenance labels.** Config hooks appear in `/hooks` tagged by origin (`managed:`, `requirements/user:`, `user:`, and so on) so you can see which layer contributed each one.
|
||||
- **No read-time expansion.** A literal `${VAR}` in a `command` or `url` reaches the hook runner unchanged, matching JSON hook-file semantics; the runner performs the single expansion.
|
||||
|
||||
---
|
||||
|
||||
## Writing Hook Scripts
|
||||
|
||||
### Input
|
||||
|
|
|
|||
|
|
@ -196,6 +196,14 @@ Whenever background work is still running while the agent looks idle — between
|
|||
|
||||
It counts running background commands, monitors, scheduled `/loop` tasks, and background subagents, and updates live as each finishes. Any of them can wake the agent for a new turn (commands and subagents on completion, monitors on events, loops on their timer), so the cue stays up until nothing is left. The running counts live only on this status line: completions land in the transcript as a single "Task completed" chip, and "Worked for" markers stay plain — the transcript never repeats or restates the running counts.
|
||||
|
||||
While a turn is waiting on background work (blocked in a `get_task_output` or `wait_tasks` call), the status line adds a hint that typing takes over immediately:
|
||||
|
||||
```
|
||||
◎ 1 command still running · send a message to interrupt
|
||||
```
|
||||
|
||||
The same hint appears as `◎ waiting · send a message to interrupt` when the agent is waiting on something with no live counter (a sleep, or work that already finished). Sending a message interrupts the wait and runs your message right away. The transcript keeps its usual shape throughout: one "Worked for" marker when the turn ends. When a completion wakes the agent and it replies, that reply gets its own "Worked for" marker; a wake the agent answers silently leaves no trace in the transcript — unless it fails, in which case a "Turn failed" line appears even for a silent wake, so a standing instruction never stops executing invisibly.
|
||||
|
||||
---
|
||||
|
||||
## Use Cases and Patterns
|
||||
|
|
|
|||
Loading…
Reference in a new issue