Architecture overview
Purpose and scope
Groundskeeper is a policy decision point for AI traffic. A gateway or application acts as the policy enforcement point: it sends an event for evaluation and applies the returned decision and transformations. The service does not proxy model traffic and does not depend on Portkey semantics internally.
The first release is a stateless Go modular monolith using Gin for HTTP routing
behind a standard net/http.Server. Streaming, a dynamic control plane, and
third-party process execution are deliberately deferred.
Context
┌────────────────────┐ ┌──────────────────────────────────────┐
│ Gateway / app PEP │─────▶│ Groundskeeper decision data plane │
│ (Portkey initially)│◀─────│ canonicalise → detect → compose │
└─────────┬──────────┘ └──────────────┬───────────────────────┘
│ │ immutable snapshot
▼ ▼
┌────────────────────┐ ┌──────────────────────────────────────┐
│ Model provider │ │ Policy and detector artefacts │
└────────────────────┘ │ Git/OCI now; control plane later │
└──────────────────────────────────────┘The gateway evaluates a request before forwarding it and evaluates a response
before returning it or executing a tool call. Those events share a fresh
step_id, but each has its own request identifier.
Evaluation flow
- The transport authenticates the integration and derives trusted tenant, workspace, application, and deployment identity. Body metadata cannot override that identity or select an arbitrary policy.
- A protocol adapter validates the envelope, preserves the raw provider payload at the boundary, and extracts canonical content segments with stable JSON Pointer paths.
- The resolver selects a fully compiled snapshot by trusted deployment binding. There is no dependency resolution or database lookup in the hot path.
- The orchestrator runs applicable checks with bounded concurrency, per-check deadlines, cancellation, and payload limits.
- Checks return findings, evidence, coverage, timings, and errors. They never return the final traffic decision.
- The deterministic composer applies the snapshot. V1 uses deny-wins plus explicit required/optional and on-error behavior.
- The transformer merges non-overlapping or policy-resolved spans using Unicode code-point offsets. Conflicts are surfaced rather than applied nondeterministically.
- The adapter maps the canonical verdict to gateway semantics. Policy blocks are normal HTTP 200 decisions; malformed requests and service failures use 4xx/5xx.
- Telemetry records identifiers, versions, timings, counts, and privacy-safe fingerprints—not prompts, completions, secrets, or matched PII.
Core model
Event
An event has a phase (input, output, tool_request, or tool_response), an
operation, a protocol, normalized segments, and trusted context. A provider body
may also be present for adapter extraction. The initial API is buffered; no
streaming completeness is implied.
Result
The core decision is only allow or block. Other concepts remain orthogonal:
findings: detector observations and evidence;modifications: deterministic replacements such as redaction;unjudged: checks that timed out, failed, were unsupported, or did not execute;policy_digestandcheck_versions: reproducibility;timings: operational visibility.
An allow decision with unjudged coverage is not equivalent to a clean result.
Finding and evidence
A finding contains a public hierarchical category, detector identity/version, severity, confidence, content path, code-point span, validation state, and structured evidence. The ordinary response can include evidence descriptors but must not echo the matched sensitive value. See the Australian taxonomy and evidence model.
Runtime components
| Component | Responsibility | Must not do |
|---|---|---|
| HTTP transport | auth context, limits, request lifecycle | classify content |
| Gateway adapter | gateway envelope mapping | decide policy |
| Protocol adapter | extract/rebuild provider payload | classify content |
| Policy resolver | select installed snapshot | compile at request time |
| Orchestrator | schedule checks and collect outcomes | silently discard failures |
| Detector | return findings/evidence/coverage | allow or block traffic |
| Composer | produce deterministic policy result | call remote systems |
| Transformer | apply resolved span operations | guess conflicting precedence |
| Telemetry sink | emit safe operational metadata | retain raw sensitive content |
Separate registries are maintained for detectors, gateway adapters, protocol adapters/content extractors, policy sources, and audit sinks. One universal plugin registry would blur different trust and lifecycle boundaries.
Go package structure
The intended package ownership is documented before code is introduced:
cmd/guardrailsd/ composition root only
internal/
app/ startup, shutdown, dependency wiring
evaluation/ orchestration, composition, transforms
model/ canonical event/result/value objects
policy/ parse, validate, compile, resolve, snapshot
correlation/ PostgreSQL repository and snapshot compiler
checks/
pii/ generic and Australian PII checks
credentials/ secret and credential leakage checks
jailbreak/ prompt-injection/jailbreak checks
safety/ content safety checks
adapter/
canonical/ direct canonical API adapter
portkey/ Portkey webhook mapping
protocol/ provider payload extractors
transport/http/ Gin routes behind net/http.Handler
platform/
config/ operator-owned configuration
telemetry/ metrics, traces, safe audit events
api/
openapi/ HTTP contract
schemas/ canonical and authoring JSON Schemas
proto/ future detector transport contract
db/migrations/ correlation/control-plane schema migrations
policies/examples/ synthetic policy examples
test/
contract/ gateway and protocol golden fixtures
conformance/ execution-mode-neutral cases and harness
evaldata/ versioned evaluation corpus manifestsMost packages remain under internal. A public Go SDK or plugin package is not
created until its compatibility obligations are understood. Gin does not cross
the transport boundary: application wiring exposes a net/http.Handler, and the
server owns read-header, read, write, idle, and graceful-shutdown timeouts.
Deployment and state
Evaluators receive a complete, verified, immutable snapshot containing compiled policy, bindings, detector configuration, and correlation data. Installation verifies digest, signer identity, provenance, schema version, and capabilities, then atomically swaps one pointer. Last-known-good and previous snapshots remain available for restart and rollback.
PostgreSQL is included from the foundation as the authoring source of truth for correlation knowledge and provenance. The compiler turns approved rows into the same immutable snapshot as policy and detector configuration. Evaluators do not query PostgreSQL for every event and continue with their last-known-good snapshot during database outages. PostGIS-backed address reference data uses a separately versioned schema or database. See Persistence.
Explicit non-goals for v1
- Proxying requests to model providers.
- Streaming/SSE enforcement or cross-chunk redaction.
- Session-wide or multi-turn obligations.
- Runtime download or execution of untrusted plugins.
- Request-time policy compilation, version resolution, or database access.
- OpenGuardrails wire compatibility (concepts inform this design only).
- Inferring identity, including Indigeneity, from content or proxies.
Quality attributes
- Determinism: same event and snapshot produce the same composed result, excluding explicitly versioned nondeterministic detectors.
- Availability: installed snapshots continue operating during control-plane and database outages.
- Latency: bounded fan-out with deadlines; numerical SLOs remain open.
- Privacy: data minimisation and metadata-only audit by default.
- Extensibility: one semantic detector contract across built-in, future gRPC, and future WASM execution.
- Explainability: decisions identify policy digest, check versions, findings, evidence classes, and unjudged coverage.