Skip to main content
Like AOF? Give us a star!
If you find AOF useful, please star us on GitHub. It helps us reach more developers and grow the community.

Context Injection Architecture

This document provides a deep dive into AOF's context injection system, which enables the same agent to operate safely across different environments, clusters, and security boundaries.

What is a Context?

A Context is an environment boundary that defines the runtime execution environment for agents. Think of it as a namespace or deployment target in Kubernetes - it isolates resources and applies specific policies.

apiVersion: aof.dev/v1
kind: Context
metadata:
name: prod-context
spec:
# WHERE the agent connects (cluster, namespace)
kubeconfig: /etc/kubernetes/prod-kubeconfig
namespace: default
cluster: prod-us-east-1

# WHAT environment the agent sees
env:
ENVIRONMENT: production
LOG_LEVEL: info
REQUIRE_APPROVAL: "true"

# WHO can approve destructive operations
approval:
required: true
allowed_users:
- U015SRE_LEAD
- U016PLATFORM_ADMIN

# HOW MUCH the agent can do (rate limits)
limits:
max_requests_per_hour: 100
max_tokens_per_request: 4096

# AUDIT trail for compliance
audit:
enabled: true
log_path: /var/log/aof/prod-audit.log

Context vs Agent

AspectAgentContext
DefinitionWhat the agent can do (capabilities)Where and how the agent operates (boundaries)
ContentsModel, instructions, toolsKubeconfig, env vars, limits, approval rules
ReusabilityReused across environmentsSpecific to one environment
Version ControlChecked into main repoMay be in separate secure repo
ChangesRequire review (change behavior)Operational changes (change boundaries)

Why Context-Agnostic Resources?

The Problem Without Contexts

Traditional approach: Agent definitions include environment details:

# ❌ prod-k8s-agent.yaml
apiVersion: aof.dev/v1
kind: Agent
metadata:
name: prod-k8s-agent
spec:
model: anthropic:claude-sonnet-4
instructions: |
You manage the PRODUCTION Kubernetes cluster.
Cluster: prod-us-east-1.example.com
IMPORTANT: Always require approval for destructive commands.
env:
KUBECONFIG: /etc/kubernetes/prod-kubeconfig
ENVIRONMENT: production
REQUIRE_APPROVAL: "true"

# ❌ staging-k8s-agent.yaml (DUPLICATE with slight changes)
apiVersion: aof.dev/v1
kind: Agent
metadata:
name: staging-k8s-agent
spec:
model: anthropic:claude-sonnet-4
instructions: |
You manage the STAGING Kubernetes cluster.
Cluster: staging-us-east-1.example.com
No approval required for destructive commands.
env:
KUBECONFIG: /etc/kubernetes/staging-kubeconfig
ENVIRONMENT: staging
REQUIRE_APPROVAL: "false"

Problems:

  • ❌ Duplicate agent definitions (90% identical)
  • ❌ Environment details leak into agent instructions
  • ❌ Hard to maintain consistency across environments
  • ❌ Changes require updating multiple files
  • ❌ No separation of concerns (logic vs deployment)

The Solution: Context-Agnostic Agents

With contexts, the agent is pure logic with no environment details:

# ✅ agents/k8s-ops.yaml (SINGLE definition, works everywhere)
apiVersion: aof.dev/v1
kind: Agent
metadata:
name: k8s-ops
spec:
model: anthropic:claude-sonnet-4
instructions: |
You are a Kubernetes operations assistant.
Help users manage cluster resources using kubectl.
Follow approval workflows when required.
tools:
- kubectl
- shell

# ✅ contexts/prod-context.yaml (PRODUCTION boundaries)
apiVersion: aof.dev/v1
kind: Context
metadata:
name: prod-context
spec:
kubeconfig: /etc/kubernetes/prod-kubeconfig
namespace: default
cluster: prod-us-east-1
env:
ENVIRONMENT: production
REQUIRE_APPROVAL: "true"
approval:
required: true
allowed_users: [U015SRE_LEAD]

# ✅ contexts/staging-context.yaml (STAGING boundaries)
apiVersion: aof.dev/v1
kind: Context
metadata:
name: staging-context
spec:
kubeconfig: /etc/kubernetes/staging-kubeconfig
namespace: staging
cluster: staging-us-east-1
env:
ENVIRONMENT: staging
REQUIRE_APPROVAL: "false"
approval:
required: false

Benefits:

  • ✅ One agent definition for all environments
  • ✅ Clear separation: agent logic vs deployment context
  • ✅ Easy to maintain and update
  • ✅ Context changes don't require agent changes
  • ✅ Security policies isolated in contexts

How Context is Injected

Context can be injected at two points in the execution lifecycle:

┌──────────────────────────────────────────────────────────────┐
│ INJECTION POINT 1 │
│ Via AgentFlow context field │
│ │
│ Slack message arrives │
│ ↓ │
│ Trigger routes to AgentFlow │
│ ↓ │
│ AgentFlow specifies context ref │
│ ↓ │
│ Context variables injected │
│ ↓ │
│ Agent executes with context │
└──────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────┐
│ INJECTION POINT 2 │
│ Via CLI --context flag │
│ │
│ $ aofctl run agent k8s-ops --context prod-context │
│ ↓ │
│ Load Context from file │
│ ↓ │
│ Context variables injected │
│ ↓ │
│ Agent executes with context │
└──────────────────────────────────────────────────────────────┘

Injection Point 1: Via AgentFlow Context (Trigger-Based)

When using triggers (Slack, Telegram, webhooks), context is specified in the AgentFlow:

# agents/k8s-ops.yaml (context-agnostic)
apiVersion: aof.dev/v1
kind: Agent
metadata:
name: k8s-ops
spec:
model: google:gemini-2.5-flash
instructions: "You are a Kubernetes ops assistant."
tools: [kubectl]

---
# contexts/prod-context.yaml
apiVersion: aof.dev/v1
kind: Context
metadata:
name: prod-context
spec:
kubeconfig: ${KUBECONFIG_PROD}
namespace: default
env:
ENVIRONMENT: production

---
# flows/slack-k8s-flow.yaml (orchestration with context reference)
apiVersion: aof.dev/v1
kind: AgentFlow
metadata:
name: slack-k8s-flow
spec:
context:
ref: prod-context # Context injection happens here
nodes:
- id: agent-process
type: Agent
config:
agent: k8s-ops
input: ${MESSAGE_TEXT}
connections:
- from: start
to: agent-process

---
# triggers/slack-prod.yaml (routes commands to flows)
apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: slack-prod
spec:
type: Slack
config:
bot_token: ${SLACK_BOT_TOKEN}
channels: [production]
commands:
/kubectl:
flow: slack-k8s-flow
default_agent: devops

Execution Flow:

1. Slack message arrives in #production channel

2. Trigger routes /kubectl command to slack-k8s-flow

3. AgentFlow loads:
- Context: prod-context (environment boundaries) ← INJECTED HERE
- Nodes: Agent workflow

4. Flow executes with prod-context:
- Agent sees env var: ENVIRONMENT=production
- Agent uses kubeconfig: ${KUBECONFIG_PROD}
- kubectl commands target production cluster

5. Response sent back to Slack

Injection Point 2: Via CLI --context Flag (Direct Execution)

When running agents directly via CLI, context is specified with --context:

# Run with production context
$ aofctl run agent k8s-ops \
--context prod-context \
--input "List all pods in default namespace"

# Execution:
# 1. Load agent: k8s-ops
# 2. Load context: prod-context ← INJECTED HERE
# 3. Inject context variables into agent execution
# 4. Agent executes with production kubeconfig
# Same agent, different context (staging)
$ aofctl run agent k8s-ops \
--context staging-context \
--input "List all pods in default namespace"

# Execution:
# 1. Load agent: k8s-ops (SAME agent)
# 2. Load context: staging-context ← DIFFERENT context
# 3. Inject staging kubeconfig
# 4. Agent executes against STAGING cluster
# No context (uses defaults)
$ aofctl run agent k8s-ops \
--input "List all pods"

# Execution:
# 1. Load agent: k8s-ops
# 2. No context specified
# 3. Uses default kubeconfig from environment (~/.kube/config)
# 4. Uses current context from kubeconfig

Context Spec Reference

Full specification of the Context resource:

apiVersion: aof.dev/v1
kind: Context
metadata:
name: string # Required: Context name
namespace: string # Optional: Namespace for isolation
labels: # Optional: Labels for filtering
environment: production
team: platform
region: us-east-1

spec:
# ===================================================================
# CLUSTER CONNECTION (where the agent operates)
# ===================================================================
kubeconfig: string # Path to kubeconfig file
# Supports env vars: ${KUBECONFIG_PROD}
# Default: ~/.kube/config

namespace: string # Default Kubernetes namespace
# Default: "default"

cluster: string # Cluster name (for audit logging)
# Optional, but recommended for multi-cluster

# ===================================================================
# ENVIRONMENT VARIABLES (injected into agent execution)
# ===================================================================
env: # map[string]string
ENVIRONMENT: production # Environment name
LOG_LEVEL: info # Logging verbosity
REQUIRE_APPROVAL: "true" # Approval flag
REGION: us-east-1 # Cloud region
# Any env vars needed by tools or agent logic

# ===================================================================
# WORKING DIRECTORY
# ===================================================================
working_dir: string # Default working directory for commands
# Default: current directory

# ===================================================================
# APPROVAL WORKFLOW (who can approve destructive operations)
# ===================================================================
approval:
required: boolean # Whether approval is required
# Default: false

allowed_users: [] # User IDs that can approve (Slack/platform IDs)
# Example: ["U015SRE_LEAD", "U016ADMIN"]

require_for: [] # Commands/patterns requiring approval
# Example:
# - kubectl delete
# - kubectl scale --replicas=0
# - helm uninstall

timeout_seconds: int # Approval timeout
# Default: 300 (5 minutes)

auto_approve_readonly: boolean # Auto-approve read-only commands
# Default: true

# ===================================================================
# AUDIT LOGGING (compliance and security)
# ===================================================================
audit:
enabled: boolean # Enable audit logging
# Default: false

log_path: string # Path to audit log file
# Default: /var/log/aof/audit.log

log_commands: boolean # Log executed commands
# Default: true

log_responses: boolean # Log agent responses (may contain sensitive data)
# Default: false

log_format: string # Log format: json, text
# Default: json

# ===================================================================
# RATE LIMITS (prevent abuse and control costs)
# ===================================================================
limits:
max_requests_per_hour: int # Max requests per hour
# Default: unlimited

max_tokens_per_request: int # Max tokens per LLM request
# Default: model's context window

max_concurrent_requests: int # Max concurrent requests
# Default: 5

max_execution_time_secs: int # Max execution time per request
# Default: 300 (5 minutes)

# ===================================================================
# SECURITY (command filtering and restrictions)
# ===================================================================
security:
allowed_namespaces: [] # Restrict kubectl to these namespaces
# Empty = all namespaces allowed
# Example: ["default", "production"]

allowed_commands: [] # Whitelist commands (empty = all allowed)
# Example:
# - kubectl get
# - kubectl describe
# - kubectl logs

blocked_commands: [] # Blacklist commands
# Example:
# - kubectl delete
# - rm -rf

readonly_mode: boolean # Force read-only operations
# Default: false

# ===================================================================
# METADATA (additional context information)
# ===================================================================
metadata:
owner: string # Team/person responsible
contact: string # Contact email/Slack
description: string # Context description

Examples: Same Agent, Different Contexts

Example 1: Production vs Staging

# agents/k8s-ops.yaml (ONE agent definition)
apiVersion: aof.dev/v1
kind: Agent
metadata:
name: k8s-ops
spec:
model: anthropic:claude-sonnet-4
instructions: "You are a Kubernetes ops assistant."
tools: [kubectl, shell]

---
# contexts/prod-context.yaml (STRICT production boundaries)
apiVersion: aof.dev/v1
kind: Context
metadata:
name: prod-context
labels:
environment: production
spec:
kubeconfig: ${KUBECONFIG_PROD}
namespace: default
cluster: prod-us-east-1

env:
ENVIRONMENT: production
LOG_LEVEL: info
REQUIRE_APPROVAL: "true"

approval:
required: true
allowed_users:
- U015SRE_LEAD # Only SRE lead can approve
require_for:
- kubectl delete
- kubectl scale --replicas=0
- kubectl apply
timeout_seconds: 300

limits:
max_requests_per_hour: 100
max_tokens_per_request: 4096

audit:
enabled: true
log_path: /var/log/aof/prod-audit.log
log_commands: true
log_responses: false

security:
readonly_mode: false
blocked_commands:
- kubectl delete namespace
- kubectl delete pv

---
# contexts/staging-context.yaml (RELAXED staging boundaries)
apiVersion: aof.dev/v1
kind: Context
metadata:
name: staging-context
labels:
environment: staging
spec:
kubeconfig: ${KUBECONFIG_STAGING}
namespace: staging
cluster: staging-us-east-1

env:
ENVIRONMENT: staging
LOG_LEVEL: debug
REQUIRE_APPROVAL: "false"
ALLOW_DELETE: "true"

approval:
required: false # No approval needed in staging

limits:
max_requests_per_hour: 500 # Higher limit for testing
max_tokens_per_request: 8192

audit:
enabled: true
log_path: /var/log/aof/staging-audit.log

security:
readonly_mode: false
# No command restrictions in staging

---
# CLI Usage
$ aofctl run agent k8s-ops --context prod-context
# → Targets production cluster
# → Requires approval for destructive commands
# → Strict rate limits

$ aofctl run agent k8s-ops --context staging-context
# → Targets staging cluster (SAME agent, DIFFERENT cluster!)
# → No approval required
# → Higher rate limits for testing

Example 2: Multi-Region Production

# agents/k8s-ops.yaml (ONE agent for all regions)
apiVersion: aof.dev/v1
kind: Agent
metadata:
name: k8s-ops
spec:
model: anthropic:claude-sonnet-4
instructions: "You are a Kubernetes ops assistant."
tools: [kubectl]

---
# contexts/prod-us-east.yaml
apiVersion: aof.dev/v1
kind: Context
metadata:
name: prod-us-east
labels:
environment: production
region: us-east-1
spec:
kubeconfig: ${KUBECONFIG_PROD_US_EAST}
cluster: prod-us-east-1
env:
REGION: us-east-1
CLUSTER_NAME: prod-us-east-1

---
# contexts/prod-eu-west.yaml
apiVersion: aof.dev/v1
kind: Context
metadata:
name: prod-eu-west
labels:
environment: production
region: eu-west-1
spec:
kubeconfig: ${KUBECONFIG_PROD_EU_WEST}
cluster: prod-eu-west-1
env:
REGION: eu-west-1
CLUSTER_NAME: prod-eu-west-1

---
# flows/us-east-flow.yaml (references US East context)
apiVersion: aof.dev/v1
kind: AgentFlow
metadata:
name: us-east-k8s-flow
spec:
context:
ref: prod-us-east # ← US region context
nodes:
- id: agent
type: Agent
config:
agent: k8s-ops
connections:
- from: start
to: agent

---
# flows/eu-west-flow.yaml (references EU West context)
apiVersion: aof.dev/v1
kind: AgentFlow
metadata:
name: eu-west-k8s-flow
spec:
context:
ref: prod-eu-west # ← EU region context (SAME agent, DIFFERENT region!)
nodes:
- id: agent
type: Agent
config:
agent: k8s-ops
connections:
- from: start
to: agent

---
# triggers/slack-regional.yaml (routes channels to region-specific flows)
apiVersion: aof.dev/v1
kind: Trigger
metadata:
name: slack-regional
spec:
type: Slack
config:
bot_token: ${SLACK_BOT_TOKEN}
commands:
/us-east:
flow: us-east-k8s-flow
description: "Manage US East cluster"
/eu-west:
flow: eu-west-k8s-flow
description: "Manage EU West cluster"
default_agent: devops

Result: One agent manages multiple production regions with different contexts!

Example 3: Tiered Access (Readonly vs Full Access)

# contexts/readonly-context.yaml (for junior engineers)
apiVersion: aof.dev/v1
kind: Context
metadata:
name: readonly-context
labels:
access_level: readonly
spec:
kubeconfig: ${KUBECONFIG_PROD}
cluster: prod-us-east-1

env:
ACCESS_LEVEL: readonly

security:
readonly_mode: true
allowed_commands:
- kubectl get
- kubectl describe
- kubectl logs
blocked_commands:
- kubectl delete
- kubectl apply
- kubectl scale

---
# contexts/admin-context.yaml (for senior SREs)
apiVersion: aof.dev/v1
kind: Context
metadata:
name: admin-context
labels:
access_level: admin
spec:
kubeconfig: ${KUBECONFIG_PROD}
cluster: prod-us-east-1

env:
ACCESS_LEVEL: admin

approval:
required: true
allowed_users:
- U015SRE_LEAD
require_for:
- kubectl delete
- kubectl scale

security:
readonly_mode: false
# Full access with approval

---
# CLI Usage
$ aofctl run agent k8s-ops --context readonly-context
# Junior engineer: Read-only access, no destructive commands

$ aofctl run agent k8s-ops --context admin-context
# Senior SRE: Full access with approval workflow

Security Implications

1. Separation of Concerns

Context injection enforces clear security boundaries:

┌─────────────────────────────────────────────────────────────┐
│ AGENT DEFINITION (business logic, version controlled) │
│ ├─ Model configuration (which LLM) │
│ ├─ Instructions (what the agent does) │
│ └─ Tools (capabilities) │
│ │
│ ✅ Can be safely reviewed and changed by engineers │
│ ✅ No secrets or environment details │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ CONTEXT DEFINITION (security boundaries) │
│ ├─ Kubeconfig secrets (cluster access) │
│ ├─ Approval rules (who can approve) │
│ ├─ Rate limits (prevent abuse) │
│ ├─ Audit logging (compliance) │
│ └─ Command restrictions (security policies) │
│ │
│ ✅ Managed by security/operations team │
│ ✅ Contains sensitive configuration │
│ ✅ May be in separate secure repo │
└─────────────────────────────────────────────────────────────┘

2. Principle of Least Privilege

Contexts enable fine-grained access control:

# Least privilege for different roles
contexts:
- name: developer-readonly
security:
readonly_mode: true
allowed_commands: [kubectl get, kubectl describe, kubectl logs]

- name: sre-operator
security:
readonly_mode: false
allowed_commands: [kubectl get, kubectl describe, kubectl logs, kubectl apply]
blocked_commands: [kubectl delete namespace]
approval:
required: true

- name: platform-admin
security:
readonly_mode: false
# Full access
approval:
required: true
allowed_users: [U015PLATFORM_ADMIN]

3. Audit Trail

All context-injected operations are logged for compliance:

{
"timestamp": "2024-01-15T10:30:00Z",
"context": "prod-context",
"cluster": "prod-us-east-1",
"namespace": "default",
"agent": "k8s-ops",
"user": "U015VBH1GTZ",
"command": "kubectl delete pod nginx-abc123",
"approval_required": true,
"approved_by": "U015SRE_LEAD",
"approval_timestamp": "2024-01-15T10:29:45Z",
"execution_time_ms": 1250,
"status": "success",
"tokens_used": 512
}

4. Secrets Management

Contexts reference secrets via environment variables:

# contexts/prod-context.yaml
spec:
kubeconfig: ${KUBECONFIG_PROD} # ← Loaded from environment
env:
AWS_ACCESS_KEY_ID: ${AWS_PROD_ACCESS_KEY}
AWS_SECRET_ACCESS_KEY: ${AWS_PROD_SECRET_KEY}

# Secrets injected at runtime (never in YAML files)
$ export KUBECONFIG_PROD=/secure/path/prod-kubeconfig
$ export AWS_PROD_ACCESS_KEY=AKIA...
$ export AWS_PROD_SECRET_KEY=secret...
$ aofctl serve --flows-dir ./flows

Best Practices

1. Keep Agents Context-Agnostic

# ✅ Good: No environment-specific details
apiVersion: aof.dev/v1
kind: Agent
metadata:
name: k8s-ops
spec:
model: anthropic:claude-sonnet-4
instructions: |
You are a Kubernetes operations assistant.
Help users manage cluster resources using kubectl.
tools: [kubectl]

# ❌ Bad: Environment details in agent
apiVersion: aof.dev/v1
kind: Agent
metadata:
name: k8s-ops
spec:
instructions: |
You manage the PRODUCTION cluster at prod.example.com.
IMPORTANT: Always require approval!
env:
KUBECONFIG: /path/to/prod-kubeconfig # DON'T DO THIS

2. Use Contexts for All Environment Differences

# Everything environment-specific goes in Context:
# - Kubeconfig path
# - Namespace
# - Approval rules
# - Rate limits
# - Audit settings
# - Security restrictions

3. Version Control Strategy

  • Agents/Flows: Check into main repo (no secrets)
  • Contexts: Separate secure repo or vault (contains secrets)
  • Bindings: Main repo (references only, no secrets)

4. Naming Conventions

# Contexts: {environment}-context or {environment}-{region}-context
prod-context
staging-context
prod-us-east-context
prod-eu-west-context

# Bindings: {platform}-{environment}-{purpose}
slack-prod-k8s-bot
whatsapp-staging-oncall
telegram-prod-incident-bot

Summary

AspectWithout ContextsWith Contexts
Agent DefinitionsDuplicate per environmentDefine once, reuse everywhere
Environment ConfigMixed with agent logicIsolated in Context resources
SecretsRisk of exposure in agent YAMLsInjected at runtime via env vars
SecurityHard to enforce policiesClear security boundaries
Audit TrailInconsistentComprehensive, context-aware
MaintainabilityUpdate multiple filesUpdate one context
ScaleDoesn't scale beyond 5-10 envsScales to 100+ environments

Key Takeaway: Context injection enables the same agent to operate safely across different environments, clusters, and security boundaries by separating business logic from deployment context.


Next Steps