Feature · Customize everything

Your rules. Your detectors. Your policies.

Every layer of AEGIS is built as a plugin contract — drop a YAML file, register a TypeScript detector, ship a DSL bundle, tune the capability-risk weights. No forking, no patching our source, no waiting on us to merge your PR. Built-ins ship with the gateway; your customisations slot in alongside.

Layer 1 · Custom scan rules

YAML in, scanner findings out.

Drop a file under .aegis/rules/. Each rule declares a pattern (regex / AST node type / tool-call shape), a severity, and a fix hint. The pre-deploy scanner runs your rules alongside the built-ins, same SARIF output.

# .aegis/rules/internal.yaml — acme inc.
- id: acme-internal-endpoint
  description: Only acme.internal hosts allowed for outbound HTTP
  severity: HIGH
  match:
    tool_call:
      name: http_post
      argument: url
      not_pattern: "^https?://[a-z0-9.-]+\\.acme\\.internal/"
  fix: "Route through the acme.internal proxy or remove the call"

- id: acme-pii-fields-in-prompt
  description: Customer SSN / DOB must never reach an LLM prompt
  severity: CRITICAL
  match:
    regex: "(\"ssn\"|\"date_of_birth\")\\s*:"
    in: ["prompt_template", "system_message"]
  fix: "Use the pseudonymisation helper at lib/redact.py"

- id: acme-only-our-anthropic
  description: Anthropic must be hit via our enterprise base_url
  severity: MEDIUM
  match:
    regex: "ANTHROPIC_BASE_URL\\s*=\\s*['\"]https://api\\.anthropic\\.com"
  fix: "Set ANTHROPIC_BASE_URL=https://aegis.acme.internal/anthropic/v1"

Rules are evaluated in order; first match wins per file. Built-ins and custom rules share the same JSON output schema so the cockpit table doesn't care where a finding came from.

Layer 2 · Custom detector plugin

TypeScript class, registered at boot.

For runtime detectors that need to look at the full tool-call context — agent identity, message history, conversation graph — the Detector plugin contract is one interface. Implement it, mount it, AEGIS runs it on every check call alongside the built-ins.

// detectors/acme-pii-policy.ts
import type { Detector, DetectorResult, CheckCtx } from '@agentguard/gateway-mcp';

export class AcmePIIDetector implements Detector {
  id   = 'acme-pii';
  kind = 'content';

  async evaluate(ctx: CheckCtx): Promise<DetectorResult> {
    // Walk every string in the tool-call arguments.
    const hits = this.findPII(ctx.toolCall.arguments);
    if (hits.length === 0) return { passed: true };
    return {
      passed:   false,
      severity: 'CRITICAL',
      decision: 'block',
      reason:   `PII fields present: ${hits.join(', ')}`,
      ontology_techniques: ['AAT-T5001'],
    };
  }

  private findPII(obj: unknown, out: string[] = []): string[] { /* ... */ return out; }
}
# Mount via tenant-config.yaml (no recompile needed)
detectors:
  - module: detectors/acme-pii-policy.ts
    class:  AcmePIIDetector
    enabled: true

Same interface every built-in detector implements (PI corpus, collusion, sequence anomaly, etc.). Your plugin sees the same context, contributes to the same decision, lands on the same audit row.

Layer 3 · Custom policy DSL

JSON in, gateway behaviour out.

The Policy DSL composes the six built-in templates + a small expression layer (all / any / not with comparators) over the gateway's classifier + anomaly + agent identity signals. Bundles are tenant-scoped — your DSL never affects other tenants.

{
  "id":   "acme-prod-rules",
  "name": "Acme — production-bot only",
  "rules": [
    {
      "name": "billing-after-hours",
      "when": {
        "all": [
          { "tool.name":     { "matches": "billing_.*" } },
          { "time.utc_hour": { ">": 18 } },
          { "agent.id":      "agent-prod-bot" }
        ]
      },
      "then": { "decision": "pending", "reason": "after-hours billing requires human review" }
    },
    {
      "name": "shell-anomalous-block",
      "when": {
        "all": [
          { "classifier.category": "shell" },
          { "anomaly.score": { ">": 0.7 } }
        ]
      },
      "then": { "decision": "block", "reason": "anomalous shell call" }
    }
  ]
}

Hot-reloadable — write the JSON, the gateway picks up the change on next config bus tick without dropping in-flight connections.

Layer 4 · Custom risk weights

Tune the capability scorer to your domain.

The NIST AI RMF capability risk scorer ships with default weights tuned for general-purpose agents. Healthcare, finance, defense each have different category sensitivities — override the weights in tenant config.

# tenant-config.yaml — healthcare deployment
capability_risk:
  weights:
    action:  0.20   # default 0.25
    egress:  0.20   # default 0.25
    secrets: 0.20   # default 0.15
    pii:     0.30   # default 0.15  ← HIPAA = PII weight ↑
    scale:   0.10   # default 0.20

  # Tighten the "blocked combo" rule: HIPAA cares about exfil even
  # without scale, so we count multi-category agents as risky earlier.
  distinct_high_action_bonus_threshold: 2   # default 3

Same scoring algorithm, different priors. The cockpit's "Agent Risk" tile recomputes per tenant.

Layer 5 · Custom compliance bundle

Add your industry's controls to the evidence endpoint.

AEGIS ships SOC 2 / ISO 27001 / NIST AI RMF / EU AI Act mapped to runtime evidence. For HIPAA / PCI / FedRAMP / sector rules, define your own mapping YAML — auditor hits one endpoint, gets the same signed JSON shape.

# compliance/hipaa.yaml
framework: hipaa
controls:
  - id: 164.308(a)(4)
    title: Information access management
    evidence:
      - source: audit_log
        filter: { action: ["policy.create", "policy.delete"] }
        explanation: "Policy lifecycle is audit-logged with actor + IP"
      - source: scim_users
        explanation: "RBAC + SCIM 2.0 IdP integration manages access"

  - id: 164.312(b)
    title: Audit controls
    evidence:
      - source: transparency_log_size
        explanation: "Append-only RFC 6962 Merkle log with daily root signatures"
      - source: witness_cosignatures
        explanation: "Sigstore-style witness cosignature when configured"

Hit POST /api/v1/compliance/bundle/hipaa and the gateway emits the same Ed25519-signed JSON artefact the built-in frameworks use.

You don't fork AEGIS. You extend it.

Every customisation lives in your own repo, version-controlled alongside your app code. AEGIS upgrades drop in cleanly — built-in updates never overwrite your extensions.