Repository navigation
Add kit-declared serviceGateways for policy-controlled agent service access #472
Description
Problem
Agent sandboxes intentionally run with a constrained network perimeter. That is the right default, but it means some useful agent capabilities are difficult or impossible to provide directly from inside the sandbox.
Examples:
- Web search / web fetch tools may need access to arbitrary public domains, while the sandbox itself should not receive broad internet egress.
- Agents may need to interact with external services such as Gmail, but should not receive the real service credentials or direct API access.
- Some operations must be technically impossible for the agent, not merely prohibited by prompt instruction. For example, a mail triage helper may be allowed to read and draft messages, but never send mail without a separate human-in-the-loop step.
A good pattern for these cases is to run a policy-controlled gateway outside the sandbox perimeter, then expose only that gateway endpoint back into the sandbox. The gateway can hold credentials, enforce allowed operations, sanitize output, log requests, and require HITL approval where appropriate.
Today, the neutral kit vocabulary can install client-side config/software in the sandbox, but it does not have a way for a kit to declare that acq should manage and expose an associated gateway service.
Proposed Shape
Add a neutral serviceGateways capability to the kit vocabulary.
A service gateway is a kit-declared, acq-managed service that runs outside the sandbox network perimeter and exposes a narrow, policy-controlled endpoint back into the sandbox.
Initial scope:
- Gateway runtime is declared with a Compose file local to the kit.
- Compose files must be part of the kit payload for v1.
- Local kit sources remain supported for development/private kits.
- Remote service-gateway kits must come from trusted kit sources.
- No privileged containers.
- Floating image tags warn.
- acq stop stops associated service gateways.
- acq rm removes associated service gateways and state.
- Guest exposure is env-var injection only.
- MCP/client config remains out of scope for this field; existing kit files/commands can install clients and write config.
- The kit declares a logical service interface, not a concrete host/guest route.
- acq and the selected backend decide how the gateway endpoint is made reachable from the sandbox.
Example sketch:
serviceGateways:
- name: vetted-web
description: "Vetted web search/fetch gateway returning inert markdown"
runtime:
compose:
file: compose.yaml
service: web-gateway
interface:
protocol: http
port: 8080
health:
path: /healthz
expose:
env:
WEB_GATEWAY_URL: urlinterface.port should be optional when acq can infer the agent-facing port unambiguously from the Compose service. If the Compose service exposes zero or multiple candidate ports, validation should require the kit to specify the port.
The final URL injected into the sandbox is resolved by acq. The kit should not encode host IPs, guest IPs, DNS names, VSOCK details, Podman machine addresses, Kubernetes service names, or other backend-specific routing details.
Why This Is Neutral
The vocabulary should not assume that:
- the sandbox runs on the same host as acq
- the service gateway runs on the same host as acq
- the selected backend is sbx or msb
- Compose is the only possible future runtime
- the gateway is local forever
The stable abstraction is:
This kit requires a service gateway with this logical interface, and the sandbox should receive a resolved URL for that gateway.
The backend-specific implementation can evolve independently. A future backend might realize the same declaration with local Podman, a remote VM, Kubernetes, a managed gateway, or some other substrate without changing the kit's user-facing intent.
Acceptance Criteria
- A trusted or local kit can declare a serviceGateways entry.
- acq can start the kit-local Compose service for the gateway.
- acq can derive or validate the gateway interface port.
- acq injects the resolved gateway URL into the sandbox environment.
- acq stop stops gateway services associated with the sandbox.
- acq rm removes gateway services and associated state.
- Remote kits from untrusted sources cannot start service gateways.
- Privileged containers are rejected.
- Floating image tags produce a warning.
- Existing guest-side kit behavior remains unchanged.
- The implementation includes an ADR covering the security boundary, lifecycle model, backend-neutral vocabulary, and why Compose files are kit-local in v1.
Notes
This likely requires coordinated changes in both repositories:
- GSA-TTS/agentic-coding-patterns: add the neutral schema and validation support for serviceGateways.
- GSA-TTS/agentic-coding-quickstart: implement parsing, lifecycle management, backend endpoint resolution, env injection, docs, ADR, and tests.
Activity
basiliskus commentedon Sep 15, 2026
Read this alongside GSA-TTS/agentic-coding-patterns#416. The vocabulary and the ADR look right to me, and the layering (routing is an adapter concern, not a schema concern) is the correct call. A few questions for the acq half, mostly about what ends up in the acceptance criteria:
Shared gateway with per-sandbox identity. I would recommend one gateway per kit per host, shared across that host's sandboxes, rather than one per sandbox: one credential copy, one approval queue, one policy and audit stream, and no Compose stack per sandbox. That only works if the gateway can tell which sandbox is calling, so acq should mint a per-sandbox token at create, inject it alongside the URL from
expose.env, and revoke it onacq rm. Without that, a host-loopback listener is reachable by any host process and any other sandbox, and a service holding real credentials cannot enforce per-sandbox policy. Either way, the ADR should state the model, since a shared gateway changes whatacq rmmay remove (reference-counted stop, not delete).What "trusted kit source" means. The ADR defers the definition to acq. Is it a pinned SHA on an allowlisted org, a first-start confirmation, or both? Related: local
ACQ_EXTRA_KITSkits get no reviewer but their author, and the patterns validator's Compose parsing is deliberately shallow. A one-time confirmation on first start of a local gateway kit, re-asked when the Compose file hash changes, would cover that gap cheaply.Lifecycle beyond stop/rm. What happens on
acq runagainst a stopped or crashed gateway (restart before attach, like startup steps re-apply?), and to a running gateway when the kit's Compose file changes underneath it (restart, warn, or keep running the old one)?Context for the interest: the login.gov data team kit currently denies every GitLab write and hand-pastes review comments. A shared policy gateway with an HITL approval step for writes is the shape that would let us retire both.
mogul commentedon Sep 16, 2026
Just because I need a place to note this, and because it's likely to be the first kit implemented: Here's a comparison of options for extracting Markdown, with benchmarks. It appears Trafilatura and Jina Reader are very capable, widely-used, and self-hostable.
mogul commentedon Sep 16, 2026
The design of
pi-web-fetchis instructive.