docs/07-agents.md
07 — Agent Integration Strategy
Layered detection, highest-signal first. Explicit signals always override heuristics. Unknown apps remain fully working terminals.
Priority stack
- Native integration — agent exposes state over a local API the
adapter can poll/subscribe (rare today; e.g. OpenCode
serveHTTP, Codexapp-server). Best-effort where officially documented. - Agent hooks / semantic events — the primary mechanism for
Phase 2. Small shims installed into each agent's hook system call
signaltty hook-event --agent <kind> --event <name> --pane $SIGNALTTY_PANE(pane id injected via env at spawn) with the hook JSON on stdin. - Standard terminal notifications — OSC 9 (iTerm2/ConEmu), OSC 99 (Kitty), OSC 777 (rxvt/Ghostty/WezTerm) scanned from the PTY byte stream server-side. Any CLI/script can emit them; zero config.
- Foreground process info —
/proc: argv, cwd, child tree, CPU. Identifies which agent runs (codex,claude,opencode,cursor-agent) and whether it is forked/busy. - Terminal state — title (
OSC 0/1/2), BEL, cursor, alt-screen. Cheap, no parsing of natural language. - Output heuristics — last resort only (spinners, prompt shapes).
Never the architecture's foundation: declarative
[[screen]]manifest rules, applied only to panes whose current process has sent no hook (see Screen rules).
Adapter interface
| 1 | trait AgentAdapter: Send + Sync { |
| 2 | /// Does this adapter own the pane's foreground process? |
| 3 | fn identify(&self, proc: &ProcessInfo) -> bool; |
| 4 | /// Map a semantic event / poll snapshot to lifecycle + attention. |
| 5 | fn lifecycle_state(&self, ev: &AdapterEvent) -> LifecycleDecision; |
| 6 | /// Native session id, if the agent reports one. |
| 7 | fn session_identity(&self, ev: &AdapterEvent) -> Option<String>; |
| 8 | /// Map hook payload / OSC / exit to a notification (or none). |
| 9 | fn notification_event(&self, ev: &AdapterEvent) -> Option<NotificationDraft>; |
| 10 | /// Official resume argv for a persisted session id, if supported. |
| 11 | fn resume_capability(&self, session_id: &str) -> Option<ResumeCommand>; |
| 12 | /// Static metadata: kind, display name, hook install recipe. |
| 13 | fn metadata(&self) -> AdapterMetadata; |
| 14 | } |
Adapters: CodexAdapter, ClaudeCodeAdapter, OpenCodeAdapter,
CursorAdapter, PiAdapter, GenericTerminalAdapter (process + title +
BEL only).
Per-agent integration (verified Sept 2026, local CLIs)
Codex CLI (codex)
Resume:
codex resume [SESSION_ID],codex resume --last; non-interactivecodex exec resume <id|--last>;codex queue,codex fork,codex archive. Session ids are UUIDs/names.Hooks:
~/.codex/hooks.json/[hooks]inconfig.toml; events includeSessionStart,UserPromptSubmit,PreToolUse,PermissionRequest,PostToolUse,Stop,SessionEnd,SubagentStop. Payload on stdin carriessession_id,transcript_path,cwd,hook_event_name,turn_id. NoNotificationevent — usenotify = ["signaltty","hook-event",…](fires onagent-turn-complete) plustui.notifications→ BEL.Session env:
CODEX_THREAD_IDequals Stop payloadsession_id.Shim:
notifyentry + hook commands callingsignaltty hook-event --agent codex. Lifecycle:UserPromptSubmit→working,PermissionRequest→blocked+permission_required,Stop→done+unread.Verified against codex 0.157.1 (Sept 2026): hooks are trust-gated — new/changed entries sit at "review required" until the user picks "Trust all and continue" in an interactive session (hash recorded under
[hooks.state]in config.toml);codex execcannot grant trust, butcodex exec --dangerously-bypass-hook-trustfires hooks (SessionStart/UserPromptSubmit/Stop/SessionEnd all observed). Hook timeouts clamp to 3s — our installer uses 3. TheStophook REQUIRES stdout to be empty or JSON on exit 0 (plain text fails the hook), sosignaltty hook-eventprints human feedback to stderr and keeps stdout silent unless--json.Codex 0.159.1 can reuse a detached shared daemon that retains a previous terminal's
SIGNALTTY_PANE/ socket. Hooks run with the daemon environment, causinghook exited with code 1(NO_SUCH_PANE) or updating another pane. Direct managed local interactive launches, split and resume use native--no-daemonwhen supported (bounded version probe); original stored argv, config/auth/trust and hook commands remain unchanged. Unsupported clients or explicit remote sessions retain their command with an integration notice. Exec/utility commands are unchanged. See ADR-0014. When typing Codex in an ordinary shell, usecodex --no-daemon. To recover an existing session, exit the TUI and runcodex --no-daemon resume --lastin the same pane. Already-running clients keep their backend until restarted; Signaltty does not stop the shared daemon or bypass hook trust.
Claude Code (claude)
- Resume:
claude --resume [id],-c/--continue,--session-id <uuid>for pinned new sessions;--settings <file>for hook injection;-p/--printnon-interactive;claude attach/logs/stop/rm/agents. - Hooks: settings JSON (
~/.claude/settings.json, project/local,--settings); eventsSessionStart,UserPromptSubmit,PreToolUse,PostToolUse,Stop,SubagentStop,Notification(idle_prompt),PreCompact. Payloadsession_idequals$CLAUDE_CODE_SESSION_ID; survives-p --resume. - Shim: settings snippet installed by
signaltty integration install claude(user-scoped, non-destructive merge).Notification→ attention directly;Stop→ done+unread.
OpenCode (opencode)
- Resume:
opencode --session <id>/-s,--continue/-c; headlessopencode run --session <id>;opencode serve+ HTTP API;opencode attach,opencode session,opencode export. - Hooks: JS/TS plugin system (
~/.config/opencode/plugins, 25+ events):session.created/updated/idle/status,command.execute.before,event,config. Plugins receiveproperties.sessionIDand can shell out. - Shim: a small plugin file calling
signaltty hook-event --agent opencode.session.status busy/idle→ working/done; idle → done+unread.serveAPI is the future native-integration path. V1 creation identity also comes fromproperties.info.id; nested provider error messages are preserved. V2session.execution.failednormalizes tosession.error(failed + error attention), while success and interruption retain idle completion behavior. Installed-plugin tests execute both loaders rather than only checking the generated source shape. Event contracts: OpenCode 2.0.25.
Cursor Agent (cursor-agent)
- Resume:
--resume [chatId](picker when bare),--continue;--print --output-format json|stream-jsonheadless;--model,--mode plan|ask. - Hooks:
~/.cursor/hooks.json;sessionStartincludes a stablesession_idmappable to the CLI pid (must reject Desktop-origin events via process ancestry check). - Shim:
hooks.jsonentry + reporter script. Screen/title fallback aligned with Codex (session-only pattern, no output regex).
Pi (pi)
- Resume:
pi --session <path|id>(partial UUID ok),-c/--continue,-r/--resumepicker;--no-sessionfor ephemeral runs. - Detection: a Node script that sets
process.title, so/proc/<pid>/cmdlinereadspiand shell-launched sessions are promoted too. - Hooks: none yet. Bundled screen rules report
workinganddone(see Screen rules); title/BEL/exit work as for a plain terminal. With no reported session id, resume is never offered. Integration path: a pi extension callingsignaltty hook-event.
Session identity & resume (see also 09)
- Identity arrives via hook payload/env only — never scraped from
terminal text while a better channel exists. Exception: resumed
sessions may fire no
SessionStart(observed:muse resumeemits only prompt/Stop); the server therefore also acceptssignaltty report-session --pane <id> --session <sid>and keeps the last known id across respawns in the same pane. resume_capability()returns the official argv (table above). The server persists it but never auto-runs it: restore offers one-click/keypress resume per pane (LIVE/RESTORED/RESUMABLE/EXITED).
Claude permission-channel probe
A live probe on 2026-10-02 verified Claude PermissionRequest Once/Deny
verdicts, including two simultaneous signaltty panes. It also records terminal
answers, timeout fallback, and ignored late verdicts. The experiment ran against
eaf8076 with a response file standing in for the GUI choice. It does not
independently verify the subsequently implemented native response bridge.
See probe results and the
repeatable experiment.
Hook attribution (pane routing)
hook-event resolves its pane in two steps: explicit pane_id
(shims read $SIGNALTTY_PANE, injected by the server at spawn), else
process-ancestry fallback — the CLI sends its pid as client_pid and
the server walks /proc parents to the deepest live pane child. The
fallback survives sandboxed agents that strip hook env, and safely
ignores foreign hooks (Cursor Desktop shares hooks.json but its
processes are never our descendants → accepted, classified nothing).
Session end after review
Claude/Codex SessionEnd and Cursor sessionEnd map to done + unread
("session ended") for a session that ends mid-turn or before any turn. When the
pane is already done or failed the hook only restates the outcome: lifecycle,
attention and the useful last message are left as they are, so a read pane stays
done/none and failed is never overwritten with done. Session identity and
resume argv from the payload are still recorded. The pane's later PTY exit
likewise does not re-raise unread on a reviewed done/failed pane. See
03.
Detection overlays: manifests (data, not code)
$XDG_CONFIG_HOME/signaltty/agents/*.toml (SIGNALTTY_AGENTS_DIR
override, --agents-dir on the server) extend one existing adapter kind
without recompiling — wrapper binaries, post-churn hook maps, custom
session keys. Loaded at startup and on agents.reload (signaltty agents reload), which swaps the whole set without touching live panes (the 10 s
process refresh may later promote a generic pane, as always); malformed files
are logged, listed by agents.list and skipped, never fatal. A directory that
cannot be listed fails the reload with IO_ERROR and keeps the active set.
signaltty integration status lists them too.
| 1 | [agent] |
| 2 | kind = "codex" # required: an existing AgentKind |
| 3 | # display_name = "…" # optional override |
| 4 | # binaries = ["codex-wrap"] # merged with the builtin list |
| 5 | |
| 6 | [session] |
| 7 | # key = "thread_id" # payload session-key override |
| 8 | # resume = ["codex", "resume", "{session_id}"] |
| 9 | |
| 10 | [lifecycle.SomeFutureHook] # any hook; unmapped hooks fall through |
| 11 | # lifecycle = "working" |
| 12 | # attention = "unread" |
| 13 | # message = "…" |
Each field falls through to the builtin adapter independently when
absent. kind must stay inside the typed taxonomy — a genuinely new
agent still needs a Rust adapter. See ADR-0009.
Screen rules (layer 6)
[[screen]] tables classify panes whose current process has sent no hook
(hooks always win, ADR-0006). Every 500 ms the server matches the rules of the
pane's kind, from every manifest of that kind, against the pane title or a
region of the visible screen (lines trimmed, empty lines dropped):
| 1 | [[screen]] |
| 2 | id = "approval" # shown in load errors |
| 3 | state = "blocked" # working | blocked | idle | hold |
| 4 | region = "bottom" # bottom (default) | title | screen | top | prompt_box |
| 5 | # | above_prompt_box | after_last_rule |
| 6 | # | after_last_prompt | before_current_prompt |
| 7 | # | without_current_prompt | osc_progress |
| 8 | lines = 12 # last (top: first) non-empty lines, 1..=200; |
| 9 | # bottom and top default to 12 |
| 10 | regex = ['Allow\? \[y/n\]'] # any match; (?m) for per-line anchors |
| 11 | # all = ['…'] # every regex must also match |
| 12 | # not = ['…'] # no regex may match |
| 13 | priority = 10 # highest match wins; ties keep file/declaration order |
A rule needs regex or all. Regions follow herdr: a horizontal rule is a
line starting with ─ (three or more, or nothing after them); prompt_box
is the text between the second-last rule and the next one (empty without
two rules), above_prompt_box everything before it (the whole screen
without a box), after_last_rule everything below the last rule (the whole
screen without one), screen the whole visible screen, bottom = screen
lines = 12,topthe firstlines(default 12). For Codex's›prompt (a line that is›or starts with›):after_last_promptis everything after the last prompt line; the current prompt is the last prompt line with no•,■,✗or✓block line after it,before_current_promptis everything above it andwithout_current_promptis the whole screen only when there is no current prompt (otherwise empty); without a prompt both prompt regions read the whole screen. A winningholdrule leaves the pane's state unchanged (a transcript viewer or model picker is not a turn state).
Agents without their own kind run as generic panes. A generic manifest
that lists binaries applies its [[screen]] rules only to generic panes
running one of those programs (an entry ending in * matches a prefix, e.g.
muse-bin-*; detection overlays match the same way); without binaries it applies to every generic
pane. The program is the spawn argv's basename, refreshed every 10 s from the
deepest non-shell descendant; a node (nodejs), bun, deno or python runtime is
named after the script it runs (pane.explain shows it as process).
osc_progress reads the latest valid OSC 9;4 payload after 9; (for example,
4;1;-1 or 4;0;0). It rejects lines and never matches when no progress
has been reported, even with an empty regex. Evidence belongs to the live PTY
scanner and is dropped on exit, close, respawn or server restart. It raises no
notification and changes no state without an applicable rule. Hooks still win.
Changing the foreground program within the same shell does not reset retained
progress. A new program can inherit it until it emits another progress signal;
process refresh scopes rules but does not track foreground generations.
pane.explain includes this evidence as osc_progress.
signaltty bundles rules for pi, opencode, cursor, claude and codex,
and for the generic programs gemini, copilot (also github-copilot,
ghcs), droid, kilo (kilo-code), qodercli (qoderclicn, qoder,
qodercn), muse (muse-code, muse-cli, muse-bin-*) and agy
(antigravity, antigravity-cli), and grok (grok-build), ported from herdr (crates/signaltty-agent/screen/); each ends
with an idle_fallback rule (priority -1000, empty regex) so a known agent
with no working or blocked sign reads as idle. User [[screen]] rules replace
the bundled ones for the panes they apply to (a kind, or for generic panes a
program); copy the bundled file to adjust it.
working → working; blocked → blocked + input_required; idle after
working → done + unread, after blocked → idle, otherwise nothing.
Leaving blocked, or the first hook taking the pane over, withdraws the
input_required a screen rule raised. No match changes nothing. A bad state, region, line count or regex rejects the
manifest at load. See ADR-0024.
Grok remains a generic agent with detection rules and launcher discovery.
Grok currently emits OSC progress only for recognized terminal brands
(Ghostty, WezTerm and recent iTerm2). signaltty advertises its own identity,
so Grok detection normally uses the screen/title fallback: an active trailing
[stop] chip matches with or without a braille spinner. OSC remains optional.
Visible option dialogs and permission/question hints outrank busy progress;
visible activity outranks stale idle titles. This does not install Grok hooks
or add native session resume support. See ADR-0030.
Live process refresh (layer 4)
Spawn argv is only the first word. Every 10s the server re-reads each
live pane's deepest shell-transparent descendant (/proc: basename +
cwd): generic panes promote to the detected kind (never demote), and
pane.cwd follows /proc/<pid>/cwd. One pane.updated per changed
pane; silence otherwise (no event spam, no snapshot churn).
Fallback behavior
No hooks installed, unknown binary, or adapter disabled → pane works
as a plain terminal with GenericTerminalAdapter: title tracking,
BEL → unread, exit code → done/failed, OSC notifications still
honored. Zero-configuration agents (raw claude with no hooks) still
get OSC + title + exit semantics.
Automatic configuration (ADR-0013)
Starting a supported agent directly from the New Workspace dialog or pane.spawn,
pane.split, pane.resume prepares its hook integration before the process starts.
Preparation uses the actual executable basename, not agent_hint or detection
manifests. The ambiguous agent command is generic by default: it may be Grok;
known Cursor aliases can still be declared explicitly in detection manifests.
Only the selected provider is configured. Existing shells and agents already
running are not reconfigured; for agents typed inside a shell use
signaltty integration install <provider> first, or start a new workspace with
that agent selected. Restarting an agent may be needed after configuration.
Shared installation merges owned command hooks, preserves foreign hooks/keys,
refuses malformed files and unrelated OpenCode plugins, refreshes stale paths,
and uses bounded advisory locking and atomic replacement. Uninstall removes
only managed commands, including inside mixed groups. Claude CLAUDE_CONFIG_DIR,
Codex CODEX_HOME, OpenCode OPENCODE_CONFIG_DIR and the default XDG OpenCode
location are honored. Explicit CLI --home isolates provider home overrides;
OpenCode still honors XDG_CONFIG_HOME.
A setup failure keeps the terminal usable and returns integration.status=error
with a notice shown in the GUI/CLI. Explicit Claude --bare or setting sources
excluding user, and OpenCode --pure, return disabled without installing.
Installation never enables a user's disabled hooks. configured/CLI installed
mean files contain managed hooks, not that events have fired. For newly written
Codex hooks the notice asks to review/trust them in /hooks; Signaltty does not
alter [hooks.state], grant trust or inject trust-bypass flags.
Native permission replies (ADR-0015)
Managed Claude and Codex PermissionRequest hooks use a dedicated waiting
reporter. It converts the provider's session_id, tool_name and tool_input
into a structured prompt with Allow once and Deny. The GUI or CLI answer
returns through the live reporter as hookSpecificOutput.decision.behavior,
not as terminal keystrokes. Reporting-only requests have no native answer route
and render read-only.
The permission reporter has a 125-second provider timeout and a bounded 120-second server wait. No answer, cancellation, supersession, disconnect or server restart produces no permission verdict, so the provider retains its own permission flow. Answers validate the request's current pane, session and deadline. The transport is transient and cannot be restored from an audit log. Ordinary status reporters retain their short timeouts and silent stdout.
Current Codex 0.159.1 accepts the same narrow allow/deny output as Claude; its tagged hook engine honors configured timeouts without the earlier three-second limit. It rejects session permission updates, modified tool input and interrupt requests, so this integration offers no permanent Always policy. Hook trust remains Codex's own interactive review. The installer preserves foreign hooks and disabled settings as before.
Sources: Claude PermissionRequest reference, Codex 0.159.1 permission execution, Codex output parser.
After successful delivery of an answer to a pending decision, the shared Store transition returns a blocked pane to working for both native permission replies and the terminal answer channel. Stale answers and non-answer clears do not resume it; ordinary tool traffic still cannot clear an unanswered blocked state.
When an agent was launched directly through a path-qualified executable, matching bare resume commands retain that selected path. Explicit manifest resume paths remain authoritative; promoted shell panes keep the adapter command. Resume arguments come from the adapter rather than the initial launch options, except the explicitly selected native automatic execution prefix on standard resume commands. Existing bare snapshot commands are repaired when resumed.
Relative executable paths supplied to pane.spawn or pane.split are anchored
to their launch directory before spawning and stored as absolute paths. Later
process directory changes therefore cannot redirect a session resume.
Legacy snapshots with a relative original executable keep the adapter command: they do not persist a reliable initial directory to anchor that relative path.
Workspace access from sandboxed harnesses
SIGNALTTY_SOCKET and SIGNALTTY_PANE identify the pane; they do not grant a
sandbox permission to connect. On Linux, a Codex shell may return EPERM even
when the socket is readable. Signaltty now registers a harness-owned stdio MCP
bridge with the same automatic setup as hooks for Codex, Claude, Cursor and
OpenCode. Restart an existing harness after signaltty integration install <agent> and approve the tools in its own settings. signaltty integration status --json reports registration, not effective trust or tool availability.
The MCP bridge does not relax network, filesystem sandbox or approval policy.
Use signaltty_context to find the hosting pane and signaltty_call for the
existing workspace/PTY API. A pane.split call can launch an agy
worker in a server-owned PTY; shell access to agy's private socket is a separate
permission. Streaming attach/subscribe and server shutdown are unavailable.
A missing/stale hosting context returns an error instead of selecting a default
server. The bridge accepts only an absolute socket from its process environment.
Managed registration locations: $CODEX_HOME/config.toml (default
~/.codex/config.toml), ~/.claude.json (or
$CLAUDE_CONFIG_DIR/.claude.json), ~/.cursor/mcp.json, and
$OPENCODE_CONFIG_DIR/opencode.json (default $XDG_CONFIG_HOME/opencode).
Codex forwards the two context variables explicitly; the other clients inherit
the launcher environment. Foreign registrations, disables and trust choices
are preserved. Project/profile/admin configuration can override global entries;
OpenCode's opencode.jsonc is left intact and can override opencode.json.
See ADR-0032.
Other bundled harnesses: audited support, 2026-10-11
Manual registrations use an absolute executable and args mcp serve; launch the
harness in a Signaltty pane so its MCP child inherits context. Do not persist a
specific pane/socket in shared configuration. These are compatibility findings,
not claims of authenticated tool-turn verification.
| Harness | Configuration path and boundary | Proof in this change |
|---|---|---|
| Codex | Automatic; MCP process outside restricted shell | Native sandbox denial before/after, real bridge worker, native config parser |
| Claude | Automatic; MCP outside Bash sandbox; --bare or excluded user sources opt out | Isolated native config-location and config-acceptance probes; configuration and managed-launch tests |
| Cursor | Automatic; approve MCP in provider settings | Configuration tests; installed CLI help; no automatic --approve-mcps |
| OpenCode | Automatic local MCP; --pure opts out; higher-priority config may override | Configuration tests and upstream format; binary unavailable locally |
| Pi | pi mcp add signaltty -- /absolute/signaltty mcp serve; --no-mcp opts out | Installed native help confirms built-in MCP; no live model turn |
| Grok | grok mcp add signaltty -- /absolute/signaltty mcp serve | Installed help confirms stdio; shared leader deployment must preserve pane context; no default leader started |
Antigravity (agy) | agy mcp add signaltty /absolute/signaltty mcp serve | Installed help confirms stdio; local MCP process boundary not verified in a model turn |
| Muse | mcpServers in its settings; installed muse mcp manages OAuth | Native help; sandboxed local process behavior unverified |
| Gemini | MCP configuration; full-process sandbox can enclose MCP children | Upstream docs only; deploy host integration explicitly if the entire CLI is sandboxed |
| Copilot | MCP configuration; local servers can report connected (sandboxed) | Upstream docs only; cannot assume host access from sandboxed MCP |
| Droid | MCP CLI supports stdio registration | Upstream docs only; host boundary unverified |
| Kilo | CLI MCP supports local servers | Upstream docs only; host boundary unverified |
| QoderCLI | MCP registration, using the installed version's command name | Upstream docs only; host boundary unverified |
If local MCP is itself denied, check the provider's sandbox/deployment and tool policy. Installing a registration does not bypass a container, admin rule or denied tool. The Signaltty CLI's EPERM/EACCES error points to these tools and setup steps instead of suggesting socket chmod.
Native approval answers and provider lifecycle hook/session-report APIs are also excluded from MCP; real harness hooks remain the source of agent identity and lifecycle evidence.
Automatic workspace titles
New GUI workspaces can use the first Codex/Claude UserPromptSubmit payload.prompt for a concise AI title. The server invokes the corresponding installed CLI's configured default model/account in a private temporary directory, with a bounded metadata request. Account quota may be used; no separate API key is needed. Generation does not interrupt the working pane. Claude has tools, skills, MCP and hooks disabled; Codex uses read-only sandboxing with executable tool features, apps/plugins/hooks and named MCP servers disabled. First-prompt hooks are required; screen-only agents/custom commands stay manually named in the GUI.
The folder name remains provisional while waiting or on failure. Rename Workspace always overrides automatic naming. There is no automatic retry, and an interrupted attempt is failed on restart. For custom installations, the server environment can set SIGNALTTY_TITLE_CODEX_BIN or SIGNALTTY_TITLE_CLAUDE_BIN to the executable path. See ADR-0031.
Automatic execution
Preferences offers Run agents without confirmations, saved as
automatic_agent_permissions in $XDG_CONFIG_HOME/signaltty/gui.json.
It defaults off, including for older or invalid settings. Enable it once to
apply native automatic execution to new installed-command Codex, Claude and
Antigravity workspaces. Shells, other agents and Custom commands keep their argv.
- Codex:
--dangerously-bypass-approvals-and-sandbox, no confirmations or native sandbox. - Claude:
--dangerously-skip-permissions. - Antigravity (
agy,antigravity,antigravity-cli):--dangerously-skip-permissions --mode accept-edits, so a planning default does not prevent execution.
Standard codex resume ID, claude --resume ID and self-reported
agy --conversation ID commands, including matching Antigravity alias commands, retain this generated prefix exactly once.
Explicit resume options win. A task.start using agent without argv
inherits the prefix from its recorded parent_pane_id only for the same supported
native provider, Codex or Claude. Antigravity workers still require explicit argv.
Explicit worker argv and different providers are unchanged. Arbitrary
initial provider flags and runtime permission changes inside a TUI are not inferred.
The setting affects new launches. Unchecking it leaves an existing session's recorded mode intact for resume. Running processes and pending decisions are unchanged; Once/Deny still serves sessions using provider-managed approvals. Authentication, hook trust and managed provider restrictions remain native. No provider configuration or live permission request is rewritten. See ADR-0036.