Skip to content

feat(yoagent-rutis): pi grants a host can ask about — exec "gate", projectTrustedFor, wakeFor - #361

Merged
yuanhao merged 3 commits into
mainfrom
feat/pi-grants
Oct 20, 2026
Merged

yuanhao merged 3 commits into
mainfrom
feat/pi-grants

Conversation

@yuanhao

@yuanhao yuanhao commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator

Asked for by yobuild (M3b step 3; spec in yobuild PR #44, docs/design.md §12). Additive config for the pi adapter; ships as yoagent-rutis 0.8.0.

  • exec / execFor[file] = "gate" — each pi.exec goes to host_approval.judge([command, ...args], cwd?) (options.cwd resolved against the adapter's cwd; omitted without one). {free: true} runs it; otherwise host_approval.ask(question, details | null, file), and only "allow" runs it. Block / unanswered / host error / cancel / no service → the existing refusal (126, reason in stderr, warn once per extension + command). The call runs in the same resolved cwd that was judged. judge bounded at 30 s; ask is the host's to time out; both race the call's signal.
  • projectTrustedFor: {file: bool} — ctx.isProjectTrusted() per extension (handlers and tools), over projectTrusted.
  • wakeFor: {file: bool} — pi.sendUserMessage and a turn-starting pi.sendMessage → host_session.wake(text, file), on one ordered chain (steering arrives in the order sent); the message is still recorded. pi's API returns void, so a refusal is a warn line (once per extension), not an error to the extension. Without the grant: unchanged.
  • Every per-file key resolves like extensions; an unknown key or a bad value refuses the load (one keyed helper).
  • host-approval.ts, host-session.ts — re-provide host_approval / host_session as pi-host-approval / pi-host-session (as host-ui.ts does ui), looked up per call, so rows without these grants need neither.
  • Fixed-answer log lines name the extension: [pi] fixed answer (<file>): …, once per extension, question and answer. context() now takes the handler's / tool's extension file.

Tests (tests/pi_test.rs): exec_gate_asks_the_host — free / allow / block / judge error / ungranted neighbour, judge and ask arguments (resolved cwd, none without one, file last), and the no-service case; a bad exec value refuses the load. trust_and_wake_per_extension — per-file trust, wakes with text and file in order (a refused one does not surface), the ungranted neighbour still throws; unknown keys and bad values refuse. Full yoagent-rutis suite (node,loader,probe), clippy, docs, fmt clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01T7iq5hpndSiHQcnAsywKuG

yuanhao and others added 3 commits October 20, 2026 22:01
…ojectTrustedFor, wakeFor

- `exec` / `execFor[file] = "gate"`: each pi.exec goes to
  host_approval.judge(argv, cwd?) then ask(question, details|null, file);
  only {free:true} or "allow" runs it, in the judged (resolved) cwd.
- `projectTrustedFor`: ctx.isProjectTrusted() per extension file.
- `wakeFor`: sendUserMessage / turn-starting sendMessage →
  host_session.wake(text, file), in order; refusals warned once.
- host-approval.ts / host-session.ts re-provide the services, as
  host-ui.ts does `ui`; fixed-answer log lines name the extension file.

Asked for by yobuild (M3b step 3).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T7iq5hpndSiHQcnAsywKuG
…say why

Review fixes for the pi grants:
- gate: argv, signal, timeout and cwd copied on entry and the call run
  from the copy (an extension could swap its args while the user was
  asked); a non-string options.cwd (a URL) is refused; cancel listeners
  removed; a Symbol sentinel for cancel.
- wakeFor: a wake while extensions load (or after unload) throws, as pi's
  runtime does; refusals deduplicated per reason, timeouts worded as such.
- refusals warned once per extension+command+kind, cancels at debug;
  lookup errors keep their text; keyed refuses a non-object setting and
  two spellings of one file.
- Test: the_gate_runs_what_it_judged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T7iq5hpndSiHQcnAsywKuG
- gate: a sparse args array is judged and run the same (Array.from);
  signal and timeout read once; an already-aborted signal between judge
  and ask cancels; a Symbol command no longer throws on the non-gate path;
  warnings keyed by kind (host answers block/unanswered, wake no-service/
  timeout/error), not free text.
- docs: judge gets no file (only ask and wake); a call without
  options.cwd runs in the adapter's cwd; wake order and its 30 s caveat;
  wakes throw once unloading starts; per-kind dedupe; stale CLAUDE.md text.
- tests: ask answers other than "allow" (unanswered, truthy, error);
  cancels before judge and during ask (a late allow runs nothing);
  projectTrustedFor false over true in tool_call and session_start;
  where gated calls run; deliverAs wakes, a quiet sendMessage does not;
  a wake while unloading throws; the fixed-answer line names its file.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T7iq5hpndSiHQcnAsywKuG
@yuanhao

yuanhao commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator Author

Second review round (code re-check, tests, comments) addressed in 7fd74a6: sparse args / options read once / abort between judge and ask / Symbol on the non-gate path / warning keys by kind; docs corrected (judge gets no file; a call without options.cwd runs in the adapter's cwd; wake order caveat; unloading); new tests for every non-allow answer, cancels before judge and during ask (a late allow runs nothing), projectTrustedFor false reaching handlers, where gated calls run, deliverAs, wakes while unloading, and the fixed-answer file in the log. pi_test 33 passed, pi_log_test passed, full suite clean.

@yuanhao
yuanhao merged commit ad4bed3 into main Oct 20, 2026
16 checks passed
@yuanhao
yuanhao deleted the feat/pi-grants branch October 20, 2026 20:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant