Skip to content

[Proposal] OpenShell integration for restricted model routing #1175

Open

Description

@afourniernv

Core target requirements landed under #1164, including host-owned execution support in #1238. This issue is still open for the OpenShell connection: pass verified policy and saved restrictions into Switchyard, then have the supervisor authorize and execute every model call.

The earlier example, #1169, closed without merging.

Background

A bank's assistant starts with public research, then reads confidential customer notes, contracts and negotiated pricing. Before those records reach a model, subsequent model calls must use the bank's approved private providers.

An administrator identifies sensitive sources in OpenShell policy. No content detector is required for this version. The agent sends ordinary requests; it cannot supply or clear the saved restriction.

Goals

  • Save the sandbox restriction before allowing access to a sensitive source. If saving fails, block access.
  • Pass that saved decision and the verified sandbox identity into Switchyard.
  • Keep normal routing within approved models, including judges, retries, answers, fallbacks and auxiliary calls.
  • Keep provider authorization, credentials and model calls under OpenShell's supervisor. Block direct provider bypasses.

Proposal

  1. An administrator marks accounts.internal.bank as sensitive.
  2. When the agent accesses that host, OpenShell calls the registered middleware with the matched policy and authenticated sandbox identity.
  3. The middleware records the sandbox as restricted before allowing source access. Public reads never clear the restriction.
  4. On later inference, the saved restriction reaches Switchyard's configured route. Stage chooses only among approved private models, as described in [Proposal] Target eligibility from trusted application requirements #1164. Requests before the restriction can use the normal models.
  5. The same supervisor authorizes the selected provider, applies credentials and makes the model call. All routing-time calls and fallbacks must follow that supervised path.

Steps 4–5 require a new routing/execution connection. They are not supplied by a YAML toggle, an existing privacy flag or Route::decide(...) alone.

flowchart TD
    A["Agent inside sandbox<br/>ordinary source and model requests"] --> O["OpenShell supervisor<br/>matched policy + verified sandbox identity"]
    P["Administrator policy<br/>sensitive account source"] -.-> O
    O -->|"Before sensitive source access"| M["Trusted middleware<br/>save restriction before allowing the read"]
    O -->|"Later model request"| R["Switchyard<br/>saved decision + configured router"]
    M -.->|"Saved sandbox restriction"| R
    R -->|"Approved model choice"| E["Same supervisor<br/>authorize provider + credentials + model calls"]
    E -->|"Standard"| S["Normal models"]
    E -->|"Restricted"| T["Bank-approved private models"]
    classDef supervisor fill:#e8f0fa,stroke:#5179a5,color:#1b2938;
    classDef approved fill:#e9f5d6,stroke:#76b900,color:#1b2938;
    class O,E supervisor;
    class T approved;
Loading

This diagram is the proposed supervisor-executed path, not a completed integration. Response inspection remains in OpenShell. Switchyard selects within the permitted models; it does not authorize network access.

Source Policy

Illustrative attachment to a registered service implementing mark_restricted:

network_middlewares:
  customer_accounts:
    middleware: switchyard
    order: 10
    on_error: fail_closed
    config:
      action: mark_restricted
    endpoints:
      include: [accounts.internal.bank]

mark_restricted is configuration interpreted by our service, not a built-in OpenShell privacy flag. The registered Rust service implements the middleware gRPC API. It validates the supervisor's identity token and checks the sandbox identity before accepting the action.

Network permissions separately allow the intended source/model traffic and block alternative provider paths. This source rule does not detect pasted sensitive text or unrelated local files. A resume retrieved from a marked source is covered; a pasted resume is not automatically covered.

Switchyard Connection

The trusted Rust caller uses Switchyard's normalized request and the existing target-label API:

request.metadata.get_or_insert_default().task_id = Some(sandbox_id);
let required_labels: &[&str] = if restricted { &["private"] } else { &[] };
require_target_labels(&mut request, required_labels.iter().copied())?;

sandbox_id is verified OpenShell identity, not agent-supplied JSON. restricted is saved policy state, not a model prediction. Here, private is an application-defined label on approved targets, not a built-in privacy setting. The route must have eligibility enabled. Passing an empty list does not clear retained requirements.

The merged label and configured-execution APIs are covered by #1164 and #1238.

The earlier example called Route::execute(...) and made provider calls itself. The proposal instead needs a supported connection that preserves request changes and approved model choices while having the supervisor make every model call. Returning only a model name does not provide provider authorization, credentials, translation or fallback execution.

Earlier Example and Validation

#1169 was closed without merging. Its Rust service under examples/openshell saved restrictions before allowing source access and returned buffered answers. It made provider calls itself, outside the sandbox supervisor's controls. It was not the proposed supervisor-executed integration.

That example was built against an unpublished OpenShell buffered-response change, rather than a released OpenShell integration.

  • The example's three Rust gRPC tests used OpenAI/Anthropic HTTP fixtures, not real models or an OpenShell sandbox. They covered policy/authentication, saved state, translation, private fallback and failure behavior.
  • An earlier real-sandbox test used synthetic account data and fixture providers. Eight model calls were audited; no confidential payload reached the normal provider fixture. That test was not rerun on the final PR revision.
  • Local-model inference passed separately. The example did not verify a full cloud-to-private run. Coverage was buffered Chat with judge-free Stage/Passthrough, not streaming, judges or auxiliary operations. Its last full-suite rerun did not finish because local disk space was exhausted.

Remaining Work and Limits

  • Define how the supervisor supplies verified policy, saved restrictions and approved provider choices to Switchyard, then executes every model call it requests.
  • Connect request/response translation, routing judges, retries, answer fallbacks and token-counting/compaction to that supervised execution path.
  • Test restriction before source release, sandbox isolation, cancellation, bypass prevention and private-only fallback. Then complete the Pi-in-OpenShell demonstration.

The earlier service used a local journal for restrictions. Runner's task requirements are bounded and in-process, not shared across replicas. Shared storage and an explicit task-reset policy remain separate work. Already-dispatched calls cannot be recalled when a later source read restricts the sandbox. Any supervisor API/protocol additions need separate review.

Feedback requested on where saved restrictions belong and how Switchyard model calls stay under supervisor authorization and execution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions