Skip to content

The system agent's defined tool set, no shell (ADR 0004 §12) - #117

Merged
ymote merged 4 commits into
mainfrom
adr0004/systools
Sep 28, 2026
Merged

ymote merged 4 commits into
mainfrom
adr0004/systools

Conversation

@ymote

@ymote ymote commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

ADR 0004 plan step 4: the system agent's tool set (§12, as accepted).

What changes

Before this PR, the system agent's turns got octos's full default tool set, octos's shell included. Now:

  • One definition in crates/kernel/src/system_tools.rs:
    • SYSTEM_AGENT_TOOLS: the system agent's default octos tools. These are supervision (peer_send_input, peer_gather, peer_list, peer_respond, peer_close), workspace-fenced file tools, memory, ask_user_question, media viewing, web_search/web_fetch (until toolbox-peers: offer the system toolbox to app agents (ADR 0002 §6, behind a feature) #108's toolbox grants replace them) and tool_search.
    • SystemAgentTools: its grants. These are toolbox tools, cross-app tools and grant_command_execution (the Settings switch, off by default). When the switch is on, the host tool terminal.run is added, and each command needs a live approval. Persisting the switch is a TODO (no Settings plumbing exists yet), and so is registering the tool on the system session (needs octos#2567 item 6).
  • The profile policy. Every kernel start writes the _main profile's tool_policy: everything a grant can give, minus octos's own shell (group:runtime: shell, bash, exec_command, write_stdin). octos applies it to every turn of the profile, including kernel wake continuations.
  • The only exclusion: octos's own shell. §12 says OctoSense hard-codes no exclusions, and delivers command execution only as a host tool with a live approval (terminal.run), run by the shell where it can be approved, audited and shown. octos's shell runs commands inside the kernel with none of that, so no grant gives it. This is the only exclusion. Schedules, sub-agents, check, git, goals, admin, plugin and MCP tools all stay grantable. If a later reading of §12 makes octos's shell grantable too, it is one line (OCTOS_SHELL, marked with a TODO).

What is enforced, and what is not

  • §12's "exactly its grants" is NOT yet enforced for the system agent. It never gets octos's shell, but otherwise it is bounded by the grantable ceiling, not its list. Its exact list needs session-targeted registration and tool lists in octos: octos#2567, reviewer item M1 (our item 5).
    • The exact-list real-kernel test is kept and #[ignore]d with that reason. Run with --ignored today, it fails, and the failure shows the gap.
  • App peers are not capped below what they can be granted. Each peer is narrowed to its grants by its turns' generic_tools (plan step 6). Host-routed tools are registered after the policy, so the policy never strips them.
  • Talk to Octos external clients are unaffected. octos confines their turns to its allowlist, which contains no shell. A real-kernel test checks this.

Whose octos home (review HIGH 1)

The desktop kernel used ~/octos-home/.octos, the person's own octos home, shared with their standalone octos. Writing a tool policy there would have changed their standalone octos.

  • OctoSense's own core dir. On every platform the core dir is now <app data dir>/octos-home/.octos. On a desktop the shell passes OctoSense's state dir, so the core dir is ~/.octosense/octos-home/.octos. $OCTOS_APP_CORE_DIR and an explicit core dir still win.
  • One-time, copy-only migration. When OctoSense's own profile does not exist yet, the kernel copies only the provider and model settings (config.llm, config.env_vars, i.e. keychain markers or saved keys) from ~/octos-home/.octos/profiles/_main.json. Nothing under ~/octos-home is ever written, moved or deleted, and no tool policy or other setting is carried over. This happens only on a desktop whose core dir comes from its data dir.
  • Defence in depth. enforce replaces only a policy OctoSense wrote ("owner": "octosense", a field octos ignores), or writes one where there is none. A foreign policy is refused with a warning, and so is the person's own ~/octos-home/.octos, policy or not.

octos changes needed

  1. Session-targeted tool lists (octos#2567 M1, our item 5), so the system agent gets exactly its grants. It would sit next to the profile policy re-apply at crates/octos-cli/src/api/ui_protocol_transport.rs:37495 and the external restriction at :37513 (and session_actor.rs:3847), set through SessionOpenParams (octos-core/src/ui_protocol.rs:2033) or a new host-only method.
  2. Host tools on the system session (our item 6). #2567 registers them per app peer only. The system session needs the same for granted toolbox and cross-app tools and terminal.run.

Tests (real kernel = octos 5e7577f built locally)

  • Kernel unit tests:
    • the policy excludes octos's shell and nothing else;
    • grants join as host tools, never as shell;
    • enforce writes ours, keeps the other keys and replaces only our own policy;
    • it refuses a foreign policy and the person's own octos home, leaving both untouched;
    • core-dir resolution and the migration: copy once, only provider settings, source tree byte-for-byte unchanged, never over an existing profile. All in temp dirs; the real ~/octos-home is never touched.
  • Kernel real kernel:
    • a system-agent turn over stdio and over Talk to Octos is offered no octos shell and all of its own tools;
    • an older OctoSense policy that allowed shell is replaced;
    • an external turn keeps its allowlist;
    • the exact-list test is ignored.
  • App-peers real kernel: no request in the question/answer exchange (host turn, wake continuation, peer turns) offers octos's shell, and the system agent cannot get a command run through an app peer.
  • Other checks: cargo build --locked -p octosense, tools/check-shell-graph.sh -p octosense, the octosense-shell and octosense-ai-host tests, and clippy on the touched crates.

🤖 Generated with Claude Code

ymote and others added 4 commits September 28, 2026 15:21
… §12)

The system agent's turns got octos's full default tool set, shell
included. `octosense_kernel::system_tools` now defines its set in one
place: supervision (peer_send_input, peer_gather, peer_list,
peer_respond, peer_close), its workspace's fenced file tools, memory,
ask_user_question, media viewing, octos's web_search/web_fetch (until
toolbox grants replace them, #108) and tool_search. No command
execution, sub-agents, peer_handoff, administration, browser, plugin or
MCP tools. Granted toolbox and cross-app tools join through
`SystemAgentTools` (none yet).

octos has no per-session tool roster, so every kernel start writes the
set into the `_main` profile as its `tool_policy` (allowlist, with
group:runtime, group:sessions and group:admin denied), replacing any
other policy. octos applies it to every turn of the profile, wake
continuations included; it is also the ceiling for app peers, AppCard
and Rinx. Talk to Octos external turns keep octos's allowlist, which
the set contains.

Tests: a real-kernel test checks a system-agent turn is offered exactly
the set over stdio and over Talk to Octos, and that an external turn
keeps its allowlist; the app-peers question/answer test checks every
request, the wake included, stays inside the set. The ADR 0007 approval
test becomes: the system agent cannot get a command run through an app
peer (no shell, nothing to approve).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd execution by grant

ADR 0004 §12 as accepted: app agents get whatever their manifest
declares and the person grants, octos generic tools included, and
command execution is a grantable host tool (terminal.run) with a live
approval, never octos's shell. The `_main` profile policy capped every
session at the system agent's list, below what an app can be granted.

The kernel now writes a ceiling instead: the system agent's tools plus
every octos generic tool an app may be granted
(APP_GRANTABLE_OCTOS_TOOLS), with octos's process tools (group:runtime,
check, git), sub-agents, peer_handoff, schedulers, goals and
administration denied (NEVER_OFFERED). App peers are narrowed to their
grants by `generic_tools` (plan step 6).

octos has no per-session tool list yet (octos#2567 item 5), so the
system agent is bounded by the ceiling, not its exact list. The
real-kernel test asserts what is enforced (no shell, nothing outside
the ceiling, its own tools present, Talk to Octos allowlist kept); the
exact-list test is kept and ignored until item 5 lands.

`SystemAgentTools::grant_command_execution` (off by default) is the
seam for the Settings grant: on, the system agent's host tools include
terminal.run (registration needs octos#2567 item 6; persisting the
switch is a TODO, no Settings plumbing exists yet).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed once

The desktop kernel's core dir was ~/octos-home/.octos, the person's own
octos home shared with their standalone octos, so writing OctoSense's
tool policy there would change their octos. The core dir is now
`<app data dir>/octos-home/.octos` on every platform; the desktop shell
passes OctoSense's state dir (~/.octosense). On first use a desktop
kernel copies only the provider and model settings (config.llm,
config.env_vars) from the shared profile into its own, once, and never
writes, moves or deletes anything under ~/octos-home.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…olicy [skip ci]

ADR 0004 §12: OctoSense hard-codes no exclusions. The `_main` profile
policy is now everything a grant can give (an empty allowlist) minus
octos's own shell (group:runtime: shell, bash, exec_command,
write_stdin), the one exception, since §12 delivers command execution
only as an approved host tool (terminal.run). Schedules, sub-agents,
check, git, goals and admin tools stay grantable.

The system agent's "exactly its grants" is not yet enforced: it is
bounded by that ceiling until octos#2567 adds session-targeted
registration and tool lists (M1, our item 5); the exact-list real-kernel
test stays ignored with that reason.

`enforce` marks the policy it writes ("owner": "octosense") and replaces
only its own: a foreign policy, or the person's own ~/octos-home/.octos,
is refused with a warning. The real-kernel test now waits for the host's
turn to finish before the external client's (one turn per session).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ymote
ymote merged commit 8b2a36c into main Sep 28, 2026
ymote added a commit that referenced this pull request Sep 29, 2026
… [skip ci]

- approvals/contacts.rs: ContactsSource (is_known for email addresses and
  Matrix IDs), ContactList/NoContacts test doubles, MailContacts reading
  Mail's host service data, and ContactsGate: off by default, on only by
  the person's Settings tap ("Use my contacts in approval rules"), kept
  owner-only in approvals/contacts.json. The router evaluates "recipients
  in contacts" through the gate.
- mail host service: contacts::known_addresses (own accounts, recorded
  send recipients, To/Cc of sent folders; never the secret store); the
  decoder keeps To/Cc; a removed account forgets its recipients.
- docs/ai-services(.zh-CN).md refreshed against main (#106, #113, #117,
  #118, #120, #124, #95, #86), linking architecture.md; architecture's
  contacts lines updated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
chrislearn pushed a commit to chrislearn/OctoSense that referenced this pull request Sep 29, 2026
Factual corrections checked against main baa90bd and octos acffad3b:
octos#2567 and OctoSense-org#106 are merged; the pin is acffad3b; generic_tools is an
exact list and omitting it keeps the whole roster (ask_user_question and
shell included), so octos's shell is kept out only by the _main
tool_policy (OctoSense-org#117); the peer link method is octos.session.open.
architecture.md and ai-services.md now reflect the system chat (OctoSense-org#132),
the peer link's shell side, the macOS sandbox and the Restart tile
(OctoSense-org#130), and the host-tool relay (OctoSense-org#145). ADRs 0002 and 0003 get dated
amendment notes for OctoSense-org#117. The system_tools.rs module doc no longer says
the command-execution switch does not exist.

Records two decisions of 2026-09-29 in ADR 0004: host.ask is dropped for
octos's ask_user_question routed by the shell (G11), and terminal.run is
process-only (G12).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ymote added a commit that referenced this pull request Oct 10, 2026
Makepad main d653bc44 carries the end of the per-app Splash runtime gates
under the ruling of 8 October 2026 (#450): #117 drops the URL, media,
socket and instruction-budget gates, and #118 the capability check before
a host.request (option (c), confirmed by the product owner). The storage
jail, inert password fields and the runtime's own checks on location,
saved lists, the camera preview and agent.notify stay; host services that
need a grant check it themselves (the device service checks the app's
grant and the person's device consent for every camera, microphone and
location call). It also carries #110-#116: renderer, Android, Linux and
TextFlow work.

The runtime overlay is rebased onto the new base: 34 patches, tree
0e7e0dac. Resolved by hand:
- Settings patch, Android IME: upstream defers HideTextIME
  (pending_ime_hide); ShowTextIME still skips a dismissed keyboard and
  publishes a new editor session, and now also cancels a pending hide;
  HideTextIME publishes the editor before deferring.
- Settings patch, GL program cache: the validation state (NeedsValidation,
  Supported, Disabled, the probe of a fresh export) is applied to
  upstream's rewritten cache functions.
- host-json-boundary and host-response-json: the capability pre-check they
  edited is gone.
- host-response-json's raw-envelope test drops its refusal mode (the
  runtime no longer builds that envelope); host-api-runtime-fixes' nested
  callback test has the host refuse the location sample instead.
makepad-map-script-api.patch is dropped: makepad#113 merged it.

video-api-smoke no longer expects the runtime to refuse an unlisted URL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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