This commit is contained in:
Spherrrical 2026-03-10 19:28:03 +00:00
parent cca95750e1
commit b19eef1806
3 changed files with 376 additions and 2 deletions

View file

@ -1,6 +1,6 @@
Plano Docs v0.4.11
llms.txt (auto-generated)
Generated (UTC): 2026-03-10T19:23:50.289501+00:00
Generated (UTC): 2026-03-10T19:27:59.878814+00:00
Table of contents
- Agents (concepts/agents)
@ -6251,6 +6251,187 @@ You can also use the CLI with Docker mode:
planoai up plano_config.yaml --docker
planoai down --docker
Kubernetes Deployment
Plano runs as a single container in Kubernetes. The container bundles Envoy, WASM plugins, and brightstaff, managed by supervisord internally. Deploy it as a standard Kubernetes Deployment with your plano_config.yaml mounted via a ConfigMap and API keys injected via a Secret.
All environment variables referenced in your plano_config.yaml (e.g. $OPENAI_API_KEY) must be set in the container environment. Use Kubernetes Secrets for API keys.
Step 1: Create the Config
Store your plano_config.yaml in a ConfigMap:
kubectl create configmap plano-config --from-file=plano_config.yaml=./plano_config.yaml
Step 2: Create API Key Secrets
Store your LLM provider API keys in a Secret:
kubectl create secret generic plano-secrets \
--from-literal=OPENAI_API_KEY=sk-... \
--from-literal=ANTHROPIC_API_KEY=sk-ant-...
Step 3: Deploy Plano
Create a plano-deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: plano
labels:
app: plano
spec:
replicas: 1
selector:
matchLabels:
app: plano
template:
metadata:
labels:
app: plano
spec:
containers:
- name: plano
image: katanemo/plano:0.4.11
ports:
- containerPort: 12000 # LLM gateway (chat completions, model routing)
name: llm-gateway
envFrom:
- secretRef:
name: plano-secrets
env:
- name: LOG_LEVEL
value: "info"
volumeMounts:
- name: plano-config
mountPath: /app/plano_config.yaml
subPath: plano_config.yaml
readOnly: true
readinessProbe:
httpGet:
path: /healthz
port: 12000
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 12000
initialDelaySeconds: 10
periodSeconds: 30
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "1000m"
volumes:
- name: plano-config
configMap:
name: plano-config
---
apiVersion: v1
kind: Service
metadata:
name: plano
spec:
selector:
app: plano
ports:
- name: llm-gateway
port: 12000
targetPort: 12000
Apply it:
kubectl apply -f plano-deployment.yaml
Step 4: Verify
# Check pod status
kubectl get pods -l app=plano
# Check logs
kubectl logs -l app=plano -f
# Test routing (port-forward for local testing)
kubectl port-forward svc/plano 12000:12000
curl -s -H "Content-Type: application/json" \
-d '{"messages":[{"role":"user","content":"tell me a joke"}], "model":"none"}' \
http://localhost:12000/v1/chat/completions | jq .model
Updating Configuration
To update plano_config.yaml, replace the ConfigMap and restart the pod:
kubectl create configmap plano-config \
--from-file=plano_config.yaml=./plano_config.yaml \
--dry-run=client -o yaml | kubectl apply -f -
kubectl rollout restart deployment/plano
Enabling OTEL Tracing
Plano emits OpenTelemetry traces for every request — including routing decisions, model selection, and upstream latency. To export traces to an OTEL collector in your cluster, add the tracing section to your plano_config.yaml:
tracing:
opentracing_grpc_endpoint: "http://otel-collector.monitoring:4317"
random_sampling: 100 # percentage of requests to trace (1-100)
trace_arch_internal: true # include internal Plano spans
span_attributes:
header_prefixes: # capture request headers as span attributes
- "x-"
static: # add static attributes to all spans
environment: "production"
service: "plano"
Set the OTEL_TRACING_GRPC_ENDPOINT environment variable or configure it directly in the config. Plano propagates the traceparent header end-to-end, so traces correlate across your upstream and downstream services.
Environment Variables Reference
The following environment variables can be set on the container:
Variable
Description
Default
LOG_LEVEL
Log verbosity (debug, info, warn, error)
info
OPENAI_API_KEY
OpenAI API key (if referenced in config)
ANTHROPIC_API_KEY
Anthropic API key (if referenced in config)
OTEL_TRACING_GRPC_ENDPOINT
OTEL collector endpoint for trace export
http://localhost:4317
Any environment variable referenced in plano_config.yaml with $VAR_NAME syntax will be substituted at startup. Use Kubernetes Secrets for sensitive values and ConfigMaps or env entries for non-sensitive configuration.
Runtime Tests
Perform basic runtime tests to verify routing and functionality.

View file

@ -243,6 +243,189 @@
</div>
</section>
</section>
<section id="kubernetes-deployment">
<h2>Kubernetes Deployment<a @click.prevent="window.navigator.clipboard.writeText($el.href); $el.setAttribute('data-tooltip', 'Copied!'); setTimeout(() =&gt; $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#kubernetes-deployment" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#kubernetes-deployment'"><svg height="1em" viewbox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"></path></svg></a></h2>
<p>Plano runs as a single container in Kubernetes. The container bundles Envoy, WASM plugins, and brightstaff, managed by supervisord internally. Deploy it as a standard Kubernetes Deployment with your <code class="docutils literal notranslate"><span class="pre">plano_config.yaml</span></code> mounted via a ConfigMap and API keys injected via a Secret.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>All environment variables referenced in your <code class="docutils literal notranslate"><span class="pre">plano_config.yaml</span></code> (e.g. <code class="docutils literal notranslate"><span class="pre">$OPENAI_API_KEY</span></code>) must be set in the container environment. Use Kubernetes Secrets for API keys.</p>
</div>
<section id="step-1-create-the-config">
<h3>Step 1: Create the Config<a @click.prevent="window.navigator.clipboard.writeText($el.href); $el.setAttribute('data-tooltip', 'Copied!'); setTimeout(() =&gt; $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#step-1-create-the-config" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#step-1-create-the-config'"><svg height="1em" viewbox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"></path></svg></a></h3>
<p>Store your <code class="docutils literal notranslate"><span class="pre">plano_config.yaml</span></code> in a ConfigMap:</p>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span><code><span id="line-1">kubectl<span class="w"> </span>create<span class="w"> </span>configmap<span class="w"> </span>plano-config<span class="w"> </span>--from-file<span class="o">=</span>plano_config.yaml<span class="o">=</span>./plano_config.yaml
</span></code></pre></div>
</div>
</section>
<section id="step-2-create-api-key-secrets">
<h3>Step 2: Create API Key Secrets<a @click.prevent="window.navigator.clipboard.writeText($el.href); $el.setAttribute('data-tooltip', 'Copied!'); setTimeout(() =&gt; $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#step-2-create-api-key-secrets" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#step-2-create-api-key-secrets'"><svg height="1em" viewbox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"></path></svg></a></h3>
<p>Store your LLM provider API keys in a Secret:</p>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span><code><span id="line-1">kubectl<span class="w"> </span>create<span class="w"> </span>secret<span class="w"> </span>generic<span class="w"> </span>plano-secrets<span class="w"> </span><span class="se">\</span>
</span><span id="line-2"><span class="w"> </span>--from-literal<span class="o">=</span><span class="nv">OPENAI_API_KEY</span><span class="o">=</span>sk-...<span class="w"> </span><span class="se">\</span>
</span><span id="line-3"><span class="w"> </span>--from-literal<span class="o">=</span><span class="nv">ANTHROPIC_API_KEY</span><span class="o">=</span>sk-ant-...
</span></code></pre></div>
</div>
</section>
<section id="step-3-deploy-plano">
<h3>Step 3: Deploy Plano<a @click.prevent="window.navigator.clipboard.writeText($el.href); $el.setAttribute('data-tooltip', 'Copied!'); setTimeout(() =&gt; $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#step-3-deploy-plano" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#step-3-deploy-plano'"><svg height="1em" viewbox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"></path></svg></a></h3>
<p>Create a <code class="docutils literal notranslate"><span class="pre">plano-deployment.yaml</span></code>:</p>
<div class="highlight-yaml notranslate"><div class="highlight"><pre><span></span><code><span id="line-1"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">apps/v1</span>
</span><span id="line-2"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Deployment</span>
</span><span id="line-3"><span class="nt">metadata</span><span class="p">:</span>
</span><span id="line-4"><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">plano</span>
</span><span id="line-5"><span class="w"> </span><span class="nt">labels</span><span class="p">:</span>
</span><span id="line-6"><span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">plano</span>
</span><span id="line-7"><span class="nt">spec</span><span class="p">:</span>
</span><span id="line-8"><span class="w"> </span><span class="nt">replicas</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">1</span>
</span><span id="line-9"><span class="w"> </span><span class="nt">selector</span><span class="p">:</span>
</span><span id="line-10"><span class="w"> </span><span class="nt">matchLabels</span><span class="p">:</span>
</span><span id="line-11"><span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">plano</span>
</span><span id="line-12"><span class="w"> </span><span class="nt">template</span><span class="p">:</span>
</span><span id="line-13"><span class="w"> </span><span class="nt">metadata</span><span class="p">:</span>
</span><span id="line-14"><span class="w"> </span><span class="nt">labels</span><span class="p">:</span>
</span><span id="line-15"><span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">plano</span>
</span><span id="line-16"><span class="w"> </span><span class="nt">spec</span><span class="p">:</span>
</span><span id="line-17"><span class="w"> </span><span class="nt">containers</span><span class="p">:</span>
</span><span id="line-18"><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">plano</span>
</span><span id="line-19"><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">katanemo/plano:0.4.11</span>
</span><span id="line-20"><span class="w"> </span><span class="nt">ports</span><span class="p">:</span>
</span><span id="line-21"><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">containerPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">12000</span><span class="w"> </span><span class="c1"># LLM gateway (chat completions, model routing)</span>
</span><span id="line-22"><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">llm-gateway</span>
</span><span id="line-23"><span class="w"> </span><span class="nt">envFrom</span><span class="p">:</span>
</span><span id="line-24"><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">secretRef</span><span class="p">:</span>
</span><span id="line-25"><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">plano-secrets</span>
</span><span id="line-26"><span class="w"> </span><span class="nt">env</span><span class="p">:</span>
</span><span id="line-27"><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">LOG_LEVEL</span>
</span><span id="line-28"><span class="w"> </span><span class="nt">value</span><span class="p">:</span><span class="w"> </span><span class="s">"info"</span>
</span><span id="line-29"><span class="w"> </span><span class="nt">volumeMounts</span><span class="p">:</span>
</span><span id="line-30"><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">plano-config</span>
</span><span id="line-31"><span class="w"> </span><span class="nt">mountPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/app/plano_config.yaml</span>
</span><span id="line-32"><span class="w"> </span><span class="nt">subPath</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">plano_config.yaml</span>
</span><span id="line-33"><span class="w"> </span><span class="nt">readOnly</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
</span><span id="line-34"><span class="w"> </span><span class="nt">readinessProbe</span><span class="p">:</span>
</span><span id="line-35"><span class="w"> </span><span class="nt">httpGet</span><span class="p">:</span>
</span><span id="line-36"><span class="w"> </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/healthz</span>
</span><span id="line-37"><span class="w"> </span><span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">12000</span>
</span><span id="line-38"><span class="w"> </span><span class="nt">initialDelaySeconds</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">5</span>
</span><span id="line-39"><span class="w"> </span><span class="nt">periodSeconds</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">10</span>
</span><span id="line-40"><span class="w"> </span><span class="nt">livenessProbe</span><span class="p">:</span>
</span><span id="line-41"><span class="w"> </span><span class="nt">httpGet</span><span class="p">:</span>
</span><span id="line-42"><span class="w"> </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/healthz</span>
</span><span id="line-43"><span class="w"> </span><span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">12000</span>
</span><span id="line-44"><span class="w"> </span><span class="nt">initialDelaySeconds</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">10</span>
</span><span id="line-45"><span class="w"> </span><span class="nt">periodSeconds</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">30</span>
</span><span id="line-46"><span class="w"> </span><span class="nt">resources</span><span class="p">:</span>
</span><span id="line-47"><span class="w"> </span><span class="nt">requests</span><span class="p">:</span>
</span><span id="line-48"><span class="w"> </span><span class="nt">memory</span><span class="p">:</span><span class="w"> </span><span class="s">"256Mi"</span>
</span><span id="line-49"><span class="w"> </span><span class="nt">cpu</span><span class="p">:</span><span class="w"> </span><span class="s">"250m"</span>
</span><span id="line-50"><span class="w"> </span><span class="nt">limits</span><span class="p">:</span>
</span><span id="line-51"><span class="w"> </span><span class="nt">memory</span><span class="p">:</span><span class="w"> </span><span class="s">"512Mi"</span>
</span><span id="line-52"><span class="w"> </span><span class="nt">cpu</span><span class="p">:</span><span class="w"> </span><span class="s">"1000m"</span>
</span><span id="line-53"><span class="w"> </span><span class="nt">volumes</span><span class="p">:</span>
</span><span id="line-54"><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">plano-config</span>
</span><span id="line-55"><span class="w"> </span><span class="nt">configMap</span><span class="p">:</span>
</span><span id="line-56"><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">plano-config</span>
</span><span id="line-57"><span class="nn">---</span>
</span><span id="line-58"><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">v1</span>
</span><span id="line-59"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Service</span>
</span><span id="line-60"><span class="nt">metadata</span><span class="p">:</span>
</span><span id="line-61"><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">plano</span>
</span><span id="line-62"><span class="nt">spec</span><span class="p">:</span>
</span><span id="line-63"><span class="w"> </span><span class="nt">selector</span><span class="p">:</span>
</span><span id="line-64"><span class="w"> </span><span class="nt">app</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">plano</span>
</span><span id="line-65"><span class="w"> </span><span class="nt">ports</span><span class="p">:</span>
</span><span id="line-66"><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">llm-gateway</span>
</span><span id="line-67"><span class="w"> </span><span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">12000</span>
</span><span id="line-68"><span class="w"> </span><span class="nt">targetPort</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">12000</span>
</span></code></pre></div>
</div>
<p>Apply it:</p>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span><code><span id="line-1">kubectl<span class="w"> </span>apply<span class="w"> </span>-f<span class="w"> </span>plano-deployment.yaml
</span></code></pre></div>
</div>
</section>
<section id="step-4-verify">
<h3>Step 4: Verify<a @click.prevent="window.navigator.clipboard.writeText($el.href); $el.setAttribute('data-tooltip', 'Copied!'); setTimeout(() =&gt; $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#step-4-verify" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#step-4-verify'"><svg height="1em" viewbox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"></path></svg></a></h3>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span><code><span id="line-1"><span class="c1"># Check pod status</span>
</span><span id="line-2">kubectl<span class="w"> </span>get<span class="w"> </span>pods<span class="w"> </span>-l<span class="w"> </span><span class="nv">app</span><span class="o">=</span>plano
</span><span id="line-3">
</span><span id="line-4"><span class="c1"># Check logs</span>
</span><span id="line-5">kubectl<span class="w"> </span>logs<span class="w"> </span>-l<span class="w"> </span><span class="nv">app</span><span class="o">=</span>plano<span class="w"> </span>-f
</span><span id="line-6">
</span><span id="line-7"><span class="c1"># Test routing (port-forward for local testing)</span>
</span><span id="line-8">kubectl<span class="w"> </span>port-forward<span class="w"> </span>svc/plano<span class="w"> </span><span class="m">12000</span>:12000
</span><span id="line-9">
</span><span id="line-10">curl<span class="w"> </span>-s<span class="w"> </span>-H<span class="w"> </span><span class="s2">"Content-Type: application/json"</span><span class="w"> </span><span class="se">\</span>
</span><span id="line-11"><span class="w"> </span>-d<span class="w"> </span><span class="s1">'{"messages":[{"role":"user","content":"tell me a joke"}], "model":"none"}'</span><span class="w"> </span><span class="se">\</span>
</span><span id="line-12"><span class="w"> </span>http://localhost:12000/v1/chat/completions<span class="w"> </span><span class="p">|</span><span class="w"> </span>jq<span class="w"> </span>.model
</span></code></pre></div>
</div>
</section>
<section id="updating-configuration">
<h3>Updating Configuration<a @click.prevent="window.navigator.clipboard.writeText($el.href); $el.setAttribute('data-tooltip', 'Copied!'); setTimeout(() =&gt; $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#updating-configuration" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#updating-configuration'"><svg height="1em" viewbox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"></path></svg></a></h3>
<p>To update <code class="docutils literal notranslate"><span class="pre">plano_config.yaml</span></code>, replace the ConfigMap and restart the pod:</p>
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span><code><span id="line-1">kubectl<span class="w"> </span>create<span class="w"> </span>configmap<span class="w"> </span>plano-config<span class="w"> </span><span class="se">\</span>
</span><span id="line-2"><span class="w"> </span>--from-file<span class="o">=</span>plano_config.yaml<span class="o">=</span>./plano_config.yaml<span class="w"> </span><span class="se">\</span>
</span><span id="line-3"><span class="w"> </span>--dry-run<span class="o">=</span>client<span class="w"> </span>-o<span class="w"> </span>yaml<span class="w"> </span><span class="p">|</span><span class="w"> </span>kubectl<span class="w"> </span>apply<span class="w"> </span>-f<span class="w"> </span>-
</span><span id="line-4">
</span><span id="line-5">kubectl<span class="w"> </span>rollout<span class="w"> </span>restart<span class="w"> </span>deployment/plano
</span></code></pre></div>
</div>
</section>
<section id="enabling-otel-tracing">
<h3>Enabling OTEL Tracing<a @click.prevent="window.navigator.clipboard.writeText($el.href); $el.setAttribute('data-tooltip', 'Copied!'); setTimeout(() =&gt; $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#enabling-otel-tracing" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#enabling-otel-tracing'"><svg height="1em" viewbox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"></path></svg></a></h3>
<p>Plano emits OpenTelemetry traces for every request — including routing decisions, model selection, and upstream latency. To export traces to an OTEL collector in your cluster, add the <code class="docutils literal notranslate"><span class="pre">tracing</span></code> section to your <code class="docutils literal notranslate"><span class="pre">plano_config.yaml</span></code>:</p>
<div class="highlight-yaml notranslate"><div class="highlight"><pre><span></span><code><span id="line-1"><span class="nt">tracing</span><span class="p">:</span>
</span><span id="line-2"><span class="w"> </span><span class="nt">opentracing_grpc_endpoint</span><span class="p">:</span><span class="w"> </span><span class="s">"http://otel-collector.monitoring:4317"</span>
</span><span id="line-3"><span class="w"> </span><span class="nt">random_sampling</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">100</span><span class="w"> </span><span class="c1"># percentage of requests to trace (1-100)</span>
</span><span id="line-4"><span class="w"> </span><span class="nt">trace_arch_internal</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span><span class="w"> </span><span class="c1"># include internal Plano spans</span>
</span><span id="line-5"><span class="w"> </span><span class="nt">span_attributes</span><span class="p">:</span>
</span><span id="line-6"><span class="w"> </span><span class="nt">header_prefixes</span><span class="p">:</span><span class="w"> </span><span class="c1"># capture request headers as span attributes</span>
</span><span id="line-7"><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="s">"x-"</span>
</span><span id="line-8"><span class="w"> </span><span class="nt">static</span><span class="p">:</span><span class="w"> </span><span class="c1"># add static attributes to all spans</span>
</span><span id="line-9"><span class="w"> </span><span class="nt">environment</span><span class="p">:</span><span class="w"> </span><span class="s">"production"</span>
</span><span id="line-10"><span class="w"> </span><span class="nt">service</span><span class="p">:</span><span class="w"> </span><span class="s">"plano"</span>
</span></code></pre></div>
</div>
<p>Set the <code class="docutils literal notranslate"><span class="pre">OTEL_TRACING_GRPC_ENDPOINT</span></code> environment variable or configure it directly in the config. Plano propagates the <code class="docutils literal notranslate"><span class="pre">traceparent</span></code> header end-to-end, so traces correlate across your upstream and downstream services.</p>
</section>
<section id="environment-variables-reference">
<h3>Environment Variables Reference<a @click.prevent="window.navigator.clipboard.writeText($el.href); $el.setAttribute('data-tooltip', 'Copied!'); setTimeout(() =&gt; $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#environment-variables-reference" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#environment-variables-reference'"><svg height="1em" viewbox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"></path></svg></a></h3>
<p>The following environment variables can be set on the container:</p>
<table class="docutils align-default">
<colgroup>
<col style="width: 30.0%"/>
<col style="width: 50.0%"/>
<col style="width: 20.0%"/>
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>Variable</p></th>
<th class="head"><p>Description</p></th>
<th class="head"><p>Default</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">LOG_LEVEL</span></code></p></td>
<td><p>Log verbosity (<code class="docutils literal notranslate"><span class="pre">debug</span></code>, <code class="docutils literal notranslate"><span class="pre">info</span></code>, <code class="docutils literal notranslate"><span class="pre">warn</span></code>, <code class="docutils literal notranslate"><span class="pre">error</span></code>)</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">info</span></code></p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">OPENAI_API_KEY</span></code></p></td>
<td><p>OpenAI API key (if referenced in config)</p></td>
<td></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">ANTHROPIC_API_KEY</span></code></p></td>
<td><p>Anthropic API key (if referenced in config)</p></td>
<td></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">OTEL_TRACING_GRPC_ENDPOINT</span></code></p></td>
<td><p>OTEL collector endpoint for trace export</p></td>
<td><p><code class="docutils literal notranslate"><span class="pre">http://localhost:4317</span></code></p></td>
</tr>
</tbody>
</table>
<p>Any environment variable referenced in <code class="docutils literal notranslate"><span class="pre">plano_config.yaml</span></code> with <code class="docutils literal notranslate"><span class="pre">$VAR_NAME</span></code> syntax will be substituted at startup. Use Kubernetes Secrets for sensitive values and ConfigMaps or <code class="docutils literal notranslate"><span class="pre">env</span></code> entries for non-sensitive configuration.</p>
</section>
</section>
<section id="runtime-tests">
<h2>Runtime Tests<a @click.prevent="window.navigator.clipboard.writeText($el.href); $el.setAttribute('data-tooltip', 'Copied!'); setTimeout(() =&gt; $el.setAttribute('data-tooltip', 'Copy link to this element'), 2000)" aria-label="Copy link to this element" class="headerlink" data-tooltip="Copy link to this element" href="#runtime-tests" x-intersect.margin.0%.0%.-70%.0%="activeSection = '#runtime-tests'"><svg height="1em" viewbox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"></path></svg></a></h2>
<p>Perform basic runtime tests to verify routing and functionality.</p>
@ -332,6 +515,16 @@
<li><a :data-current="activeSection === '#starting-the-stack'" class="reference internal" href="#starting-the-stack">Starting the Stack</a></li>
</ul>
</li>
<li><a :data-current="activeSection === '#kubernetes-deployment'" class="reference internal" href="#kubernetes-deployment">Kubernetes Deployment</a><ul>
<li><a :data-current="activeSection === '#step-1-create-the-config'" class="reference internal" href="#step-1-create-the-config">Step 1: Create the Config</a></li>
<li><a :data-current="activeSection === '#step-2-create-api-key-secrets'" class="reference internal" href="#step-2-create-api-key-secrets">Step 2: Create API Key Secrets</a></li>
<li><a :data-current="activeSection === '#step-3-deploy-plano'" class="reference internal" href="#step-3-deploy-plano">Step 3: Deploy Plano</a></li>
<li><a :data-current="activeSection === '#step-4-verify'" class="reference internal" href="#step-4-verify">Step 4: Verify</a></li>
<li><a :data-current="activeSection === '#updating-configuration'" class="reference internal" href="#updating-configuration">Updating Configuration</a></li>
<li><a :data-current="activeSection === '#enabling-otel-tracing'" class="reference internal" href="#enabling-otel-tracing">Enabling OTEL Tracing</a></li>
<li><a :data-current="activeSection === '#environment-variables-reference'" class="reference internal" href="#environment-variables-reference">Environment Variables Reference</a></li>
</ul>
</li>
<li><a :data-current="activeSection === '#runtime-tests'" class="reference internal" href="#runtime-tests">Runtime Tests</a><ul>
<li><a :data-current="activeSection === '#gateway-smoke-test'" class="reference internal" href="#gateway-smoke-test">Gateway Smoke Test</a></li>
<li><a :data-current="activeSection === '#model-based-routing'" class="reference internal" href="#model-based-routing">Model-Based Routing</a></li>

File diff suppressed because one or more lines are too long