#9931: feat(message): configurable outbound gate preflight
stale
Adds an optional, fail-closed (default) outbound gate for message sends.
- New config: `tools.message.gate` (enabled/mode/command/timeoutMs/env)
- Gate runs before `executeSendAction` and can deterministically block sends.
- Gate is an external command that receives JSON on stdin and returns `{allow, reason, policyVersion?}`.
Motivation: MVRSA-style separation of justification/constraint from execution ("reasons can stop action") + support HexMem-backed policy.
Follow-ups:
- Extend to other outbound actions (react/poll/etc)
- Provide a reference gate implementation that queries HexMem
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR introduces an optional preflight “outbound gate” for message sends, controlled by `tools.message.gate` (enabled/mode/command/timeoutMs/env). When enabled, `handleSendAction` runs an external command before `executeSendAction`; the command receives the send context as JSON on stdin and returns `{ allow, reason, policyVersion? }` on stdout. The result deterministically blocks sends when `allow` is false, with configurable fail-open vs fail-closed behavior on gate failures/timeouts.
The change is localized to message send flow (`src/infra/outbound/message-action-runner.ts`) plus a new gate runner (`src/infra/outbound/outbound-gate.ts`) and the corresponding config typing (`src/config/types.tools.ts`).
<h3>Confidence Score: 3/5</h3>
- This PR is close to mergeable but needs fixes in the gate runner to avoid type-check/runtime lifecycle issues.
- Core integration is straightforward, but the new gate runner returns unvalidated JSON fields as typed strings and can resolve the gate promise multiple times after a timeout, which can cause TypeScript build failures and unpredictable behavior under timeouts.
- src/infra/outbound/outbound-gate.ts
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
**Context used:**
- Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8))
- Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13))
<!-- /greptile_comment -->
Most Similar PRs
#8713: feat: gateway memory monitor, install linger, docs and failover
by quratus · 2026-02-04
72.1%
#9511: feat: add tool error fallback toggle
by bolismauro · 2026-02-05
72.0%
#20492: feat(cron): gate script evaluated before agent turn
by clawmander · 2026-02-19
71.3%
#7353: fix: prevent silent message drops after config.patch restart
by 18-RAJAT · 2026-02-02
71.0%
#10034: Don't crash gateway on transient unhandled fetch failures
by gigq · 2026-02-06
70.6%
#12953: fix: defer gateway restart until all replies are sent
by zoskebutler · 2026-02-10
70.4%
#6466: fix(gateway): add handshake timeout and connection error handling
by jarvis-raven · 2026-02-01
70.2%
#6302: fix: Add timeouts to prevent indefinite hangs (issues #4954, #4956,...
by batumilove · 2026-02-01
70.2%
#19923: feat: track held messages during compaction gate and split verifica...
by PrivacySmurf · 2026-02-18
70.1%
#3396: Config: gateway.unhandledRejections (warn|exit)
by diegoaledesma · 2026-01-28
70.0%