Repository navigation
ADR 0004: the peer link for process apps, process sandboxes, Restart tile for dead process apps [skip ci] - #130
Merged
Merged
Conversation
…its tile [skip ci] ADR 0004 §3, §11 and §2. tools/native_apps.py validates and generates each app's `sandbox` (network, processes) and `storage` (accounts, external) into native_apps.rs. sandbox/ builds one policy per app and applies it in spawn_client: - macOS: a Seatbelt profile through /usr/bin/sandbox-exec (cargo's runner for a `cargo run` launch, so the build stays outside): the person's data roots closed but for the jail, its secrets and `external`; program and resources read-only; network `none` = the hub on loopback only; `processes: false` = no fork or exec. - Linux: Landlock (paths; TCP ports from ABI 4) and seccomp, installed between fork and exec, best-effort with the layers logged. - Windows: a documented AppContainer TODO; the log says unsandboxed. - No child inherits OCTOS_* / OCTOSENSE_* (scrub_env), and a cargo launch's [env] host variables are unset in its runner. - OCTOSENSE_SANDBOX_NARROW narrows an app for test runs (only removes). A process app that dies unexpectedly now keeps its tile, closed with "<App> stopped" / "Click to restart" (MpRunView::show_stopped), and a press restarts it; the shell and other apps keep running. The processes_available() test now covers the phone targets too. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ADR 0004 §5. peer_link/ gives a process app its own channel to its octos
app agent on its hub socket ("octos_peer" frames, never the AI bus):
requests on its one peer through the app-peers service in-process
modules get (an adapter until octos#2567's relay), and the tool-call
half behind seams for the relay (set_tool_relay, tool_call, tool_cancel,
context_owner, has_link, close_account).
Identity is the socket's slot; a call's account, context and client come
from the shell's own context records. Links open only for apps whose
native-apps.json entry grants agent.octos, and requests need consent.
The shell keeps the host obligations (once per call, nothing after
cancel, acknowledge before any sheet; confirmations through the #120
router, whose decisions get their own peerlink: route), and a dead
process fails its calls (outcome_unknown unless read-only), closes its
contexts and keeps the peer.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ymote
force-pushed
the
adr0004/peer-link
branch
from
September 29, 2026 01:11
d33e160 to
5424151
Compare
This was referenced Sep 29, 2026
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ADR 0004 plan step 8 (the coordinator's step 7): the peer link for native apps hosted in their own process, and the process sandboxes (§3, §5, §11 enforcement table). Crash isolation (§2) is checked and fixed on the way.
The peer link (
crates/shell/src/peer_link/)Customframes under the"octos_peer"envelope, taken before the WM and AI-bus parsers and never registered with the bus (lib.rson_app_msg).request {req_id, method, args}(octos.session.open|history,octos.turn.start|interrupt,octos.context.close) andtool_result {call_id, ok, data | error | awaiting_confirmation}. Down:reply, streamedevent,tool_call {call_id, name, args, risk, confirm_required, timeout_ms, account, context_id, client, caller},tool_cancel,context_closed.native-apps.jsonentry grantsagent.octos(all services in developer mode); each request needsconsent::granted(the first-use sheet asks once, throughapprovals::module_gate); each method must be granted.confirm: hostcalls wait on the ADR 0004 §8/§4: approval router, standing rules, shell sheets, first-use consent #120 router's sheet (decisions come back on their ownpeerlink:route inapprovals/mod.rs);confirm: appcalls go to the app withconfirm_required, and a result without the app'sawaiting_confirmationfirst is refused. Deadlines time calls out and cancel them at the app.outcome_unknownunless they only read), closes its request contexts and keeps the peer: a restarted process gets the same service, not a new peer.crates/app-peers' broker viahosted::launch, underoctos-core), as an adapter until #2567's relay exists.makepad_ai_services::peer, ai-services: the peer link client (OctoSense ADR 0004 §5) makepad#54, merged) serves in-process modules too. The shell parses the same JSON with serde_json and needs no Makepad type, so nothing here waits on a repin; the fixture test pins the exact frames the client writes.Seams for home-96 (octos#2567 relay)
peer_link::set_tool_relay(Box<dyn ToolRelay>)ToolRelay::acknowledged(app, call_id)/finished(app, call_id, ToolCallResult)Ok,Error,OutcomeUnknown)peer_link::tool_call(app, KernelToolCall) -> Result<(), Refused>peer/tool/call(kernelcontext_id, stampedcaller,risk,timeout_ms,trigger,outcome_unknown);Refused::{NotConnected, Duplicate, UnknownContext, Declined}peer_link::tool_cancel(app, call_id)peer_link::context_owner(app, kernel_context_id)<nonce>-<handle>ids)peer_link::has_link(app),peer_link::close_account(app, account)RecordingToolRelayis the test double. Nothing incrates/app-peersorcrates/ai-hostchanged.Process sandboxes (
crates/shell/src/sandbox/)Built generically from each entry's
sandboxandstorage(now generated intonative_apps.rs:network,processes,accounts,external;tools/native_apps.pyvalidates them) and applied inclients::spawn_client:/usr/bin/sandbox-exec; acargo runlaunch gets it as cargo'srunner, so only the app is sandboxed, never the build. The person's data roots (home,/Volumes) are closed except the jail, its secrets andexternal; the program and resources are read-only;network: noneallows only the hub on loopback;processes: falsedenies fork and exec.sandbox-exec/sandbox_initare deprecated in Apple's headers but remain the working mechanism; if it disappears the app runs unsandboxed with a logged warning.processes: false), installed between fork and exec, best-effort with the layers that took in the log. A dev launch through cargo sandboxes the build too, with the build's paths added. Compile-checked only; not run.sandbox/mod.rs); the app runs unsandboxed and the log says so.OCTOS_*orOCTOSENSE_*(host and external tokens, kernel and core dirs, the vault):sandbox::scrub_envon every spawn.OCTOSENSE_SANDBOX_NARROW=<app,…>narrows an app to its jail and no network for test runs; it can only take rights away.Crash isolation
A process app that died was removed with a notification. Now its tile stays, closed (" stopped", "Click to restart"), its peer link, bus registration and pane links go, and a press restarts it through the existing Restart action (
ClientSlot::stops_in_place,MpRunView::show_stopped).Checks
All run locally on macOS (arm64), after rebasing on main (makepad 4fdcfccc):
cargo check --locked -p octosenseand--features mobile-apps; fromphone/:cargo check --locked -p octosense-home --features mobile-appscargo test --locked -p octosense-shell --lib(455 passed) and fromphone/with--features mobile-apps(466 passed), including 12 peer-link tests (framing against the Makepad client's fixture frames, identity stamping, grants/consent, once per call, nothing after cancel, ack before sheet,confirm: appack, deadlines, death, sign-out), 7 sandbox tests (a real child under a jail-only profile reads its jail and secrets and is refused a file beside it, another app's jail, a write outside, a non-hub TCP connection and a fork; the Terminal's broad policy; the profile's rule order; noOCTOS_*/OCTOSENSE_*in a child's environment; cargo[env]host variables) and the new crash-tile andprocesses_available()teststools/check-shell-graph.sh -p octosenseand-p octosense-home;tools/setup.py --check --cargo;tools/native_apps.py --check;python3 -m unittest discover -s tools -p 'test_*.py'MAKEPAD_HIDE_WINDOWS=1 MAKEPAD_REMOTE, ended with/gq): the Terminal as a process under its sandbox narrowed withOCTOSENSE_SANDBOX_NARROW=terminalrendered and ran its shell; typed into it,ls ~gave "Operation not permitted",curl https://example.comfailed to resolve, the jail was writable, andenvshowed noOCTOS*variable although the shell was started with a fakeOCTOS_AUTH_TOKENandOCTOS_APP_CORE_DIR. Reference (network none, no processes, jail only) rendered normally under its profile and its environment had noOCTOS*variable.kill -9of either child left the tile as " stopped / Click to restart" with the shell running; a click restarted it.sandbox/compile-checked forx86_64-unknown-linux-gnuandaarch64-unknown-linux-ohos, and Windows (x86_64-pc-windows-msvc) through a standalone crate holding the same files. A whole-shellcargo check --target x86_64-unknown-linux-gnustops inring's C build (no Linux C cross toolchain here). Unverified: nothing ran on Linux or Windows.cargo test -p makepad-ai-services --lib(61 passed), ai-services: the peer link client (OctoSense ADR 0004 §5) makepad#54, merged.Follow-ups
sandbox/mod.rs).PendingPeerLinksinmodule_host.rs, now that the pin carries the client, so an in-process Makepad module uses the sameOctosPeerAPI.🤖 Generated with Claude Code