Skip to content
ENES
A robed traveler stands at a carved-stone archway on the right, gazing out over pale desert dunes where a winding path leads toward distant citadel walls under a soft daytime sky.

ENES Lights the way Carries the load

Beside you Faithful to the end

ENES tasks

What ENES can help you do

Pick a starting point. ENES opens a conversation, reads your tenant first, and walks you through it — proposing every change for your approval.

On the name

أنس

Anas · أنس

“ENES — named for Anas ibn Malik, who served faithfully for ten years and was never once reproached, and who carried what he was given, word for word, all his life. The name means companionship: the comfort of not facing the hard work alone.”

What ENES holds to

Reads before it actsIt looks at what's actually in your tenant first, and grounds everything it says in what it found there.
Proposes, never imposesEvery change is shown to you in full before anything happens. Nothing is applied until you approve it.
Honest, and calm about itIf something goes wrong, it tells you plainly what it saw and what to try — and it never puts that on you.
Built to be readGenerous type, gentle motion, and high contrast in both themes. Everything is keyboard-reachable and scales to your comfort.
Portkey · AI gateway

Draft a Portkey gateway config

Describe, in plain words, what you want your AI gateway to do — provider routing, fallback, load-balancing, caching, or a Prisma AIRS scan on the traffic. ENES writes a valid config, grounded in the Portkey schema, for you to copy. Nothing is created in your tenant.

1Start from a common config— optional; your pick fills the box below
2Describe what you want— tweak the starter, or write your own
Grounded in the Portkey schema · never invented · copy-only
Drafting your config…
{{ configErr }}
Portkey config
{{ configCode }}
This didn’t come back as strict JSON — read it over before using it.
{{ configExplain }}
3Deploy this config— optional; ships it live to your Portkey account

Creates the config above in your account. Add your Prisma AIRS guardrail ID to scan its traffic; the key is used once and never stored.

Mint a virtual key from a provider secret
Creates real resources in your account.
{{ pdErr }}
Config created
Config ID: {{ pdResConfigId }}
Slug: {{ pdResSlug }}
Virtual key: {{ pdResVkey }}
{{ pdResAirs }}
Use it
{{ pdSnippet }}
Send a real request through it — model, usage, policy, raw.
Testing · Prisma AIRS

Test a profile with a sample prompt

Like Postman for Prisma AIRS: send a real prompt through a security profile and see whether it is allowed or blocked, and which detectors fire. ENES sends the scan for real. Your API key is used for this one call only — never stored.

1Connection— your scan token, the profile, and the region
2Test prompt— pick a language, then tap one or more types (each fires its own scan), or write your own
Language
{{ scanSelLine }}
{{ ch.label }}
{{ ch.text }}
Each selected prompt is sent as its own scan · results depend on which detectors your profile enables
Sending the scan to Prisma AIRS…
{{ scanErr }}
3Results
{{ scanSummary }} Each result below has its own Formatted / Raw view
#{{ rr.num }} {{ rr.label }}
{{ rr.promptEcho }}
{{ rr.verdictText }} HTTP {{ rr.status }} — not completed
Category: {{ rr.category }}
Detectors that fired
{{ h.label }}
No detectors fired — the prompt passed clean.
Latency: {{ rr.latency }} ms scan_id: {{ rr.scanId }} report_id: {{ rr.reportId }} transaction_id: {{ rr.echoTxn }} session_id: {{ rr.echoSession }}
Prisma AIRS returned HTTP {{ rr.status }} for {{ rr.endpoint }}. The full response is in Raw JSON — common causes are an invalid key, a profile that doesn’t exist, or the wrong region for this key.
Response · HTTP {{ rr.status }}
{{ rr.rawJson }}
Request sent (no key)
{{ rr.reqJson }}
API call we sent
{{ rr.curl }}

Each prompt is sent as its own separate scan. Keys are masked as <your-api-key> in every “API call we sent” box — drop yours in to replay any of them.

Guardrails · Prisma AIRS

Build custom-topic guardrails

Describe your assistant and what to keep in or out of bounds. ENES drafts proper AIRS custom topics — inside every official limit — then creates them in your tenant, attaches them to a profile as allowed or blocked, and can test a prompt against it. Nothing is claimed the tenant didn’t actually save.

1Target— how ENES should apply these
No saved AIRS tenants. Connect one with its management credentials, or switch to One-time tenant or Generate only above.
Reading profiles from the tenant…
{{ tgProfilesErr }}

This tenant's management credentials — used once for this push, never stored.

ENES will only draft the topics — nothing touches a tenant. You’ll get the cards plus copy-ready CustomTopicObject JSON to create in SCM yourself.
2Describe the boundary
Within AIRS limits: ≤20 topics · name ≤100 · description ≤250 · ≤5 examples ≤250 each · English.
{{ tgDraftErr }}
Drafting your custom topics…
3Drafted topics— fully editable before anything is pushed
{{ tgSummary }}
More than 20 topics — AIRS allows at most 20 per profile. Remove some before pushing.
{{ c.badgeText }}
{{ c.nameMeter }}
{{ c.descMeter }}
Examples
{{ ex.meterLabel }}
Over limit: {{ c.errorText }} combined {{ c.combinedMeter }}

{{ tgNotes }}

{{ tgJson }}
4Action
target: {{ tgTargetLine }}
Generate-only — copy these and create them in SCM yourself.
{{ tgApplyErr }}
{{ tgTestErr }}
Created & attached to {{ tgApplyProfile }} — verified ✓
Couldn’t complete at the {{ tgApplyStage }} step — {{ tgApplyErrMsg }}
{{ r.label }} {{ r.sub }}
{{ tgTestVerdictText }} Topic violation category: {{ tgTestCategory }}
{{ d.label }}
Performance · Prisma AIRS

Stress / volumetric test

Fire a controlled burst of scans through a profile to see how it holds up under load — throughput, latency percentiles, and rate-limit behavior — so you know the real numbers before a customer does.

1Target— where the scans go
Nothing leaves ENES — scans are simulated, no tenant and no credit spend. Perfect for shaping the load and reading the report. Switch to a saved tenant or a manual key to fire for real.
No saved AIRS tenants yet. Connect one, or stay on Dry run.
Reading profiles from the tenant…
{{ stProfilesErr }}
Live runs fire real scans and consume scan quota. Keep the total modest.
Fires real scans against the tenant behind this key and consumes scan quota. The key is used only for this run — never stored. Keep the total modest.
2What to fire— the corpus slice
Loading the attack catalog…
⚠ {{ stMetaErr }}
{{ stCountLabel }}
3Load shape— rate, ceiling, and how much
sec
Advanced · concurrency
worker threads — raise if achieved RPS lags target
{{ stReadoutLabel }}
⚠ {{ stTpmWarn }}
{{ stCycleNote }}
{{ stRunHint }}
{{ stError }}
{{ stProgTitle }}{{ stProgCounts }}
{{ stLiveRps }}
send rps
{{ stLiveElapsed }}
elapsed
{{ stLiveDone }}
completed
Paused — no scans firing
Results
rate bound by {{ stBoundBadge }}
{{ c.value }}
{{ c.label }}
{{ c.sub }}
Added delay — AIRS scan latency (ms)
{{ b.ms }}
{{ b.label }}
⚠ {{ stQueueWarn }}
Detection under load — did each category get its expected verdict (click a row to see the scans)
Attack categoryExpected-verdict rateVerdicts · block · allow · err
{{ r.caret }} {{ r.label }}{{ r.correct }}{{ r.detail }}
{{ stDrillTitle }} — sent traffic & verdicts
Loading scans…
{{ stDrillErr }}
{{ d.verdict }}
{{ d.promptShort }}
{{ d.meta }}{{ d.note }}
{{ stDrillNote }}
Errors
[{{ e.http }}] ×{{ e.count }} {{ e.msg }}
{{ stReportFooter }}
Previous runs— saved & safe to refresh; click one to reopen its report, drill-down, and export
{{ r.title }}
{{ r.stat }}
{{ r.when }}

How can I help?

Tell me what you'd like to set up in Prisma AIRS. I'll read what's there, walk you through it, and change nothing until you say so.

{{ activeTitle }}
{{ m.text }}
{{ m.text }}
{{ m.text }}
Review & approve

{{ m.card.intro }}

Profile: {{ m.card.profile }}
{{ c.label }}{{ c.from }} {{ c.to }}

{{ m.card.scope }}

Approved — applied to your tenant.
Left unchanged, exactly as you asked.
Test scan — nothing changed
“{{ m.card.prompt }}”
{{ m.card.verdict }}scanned in {{ m.card.latency }}
{{ mt.cat }}{{ mt.level }}

{{ m.card.note }}

Lighting the way…
{{ voiceErr }}
Delete conversation?

{{ confirmTitle }}” will be permanently removed. This can’t be undone.

Rename conversation

What should I call you?

So I can address you properly. Just your first name is perfect.

Add a connection

Connect the systems ENES helps you secure. Credentials are encrypted at rest and never kept in your browser.

Security platforms
Koi Agentic endpoint security Soon
Clouds
AWS Wire AIRS into your AWS Soon
GCP Wire AIRS into your GCP Soon
{{ connectTitle }}

{{ connectBlurb }}

{{ connectErr }}

Portkey · AI gateway

Gateway guardrail bench

Fire an attack corpus through your live Portkey gateway and see, prompt by prompt, what an AIRS-guarded config actually blocks — and what a baseline config lets through. Real gateway calls; ENES reports exactly what comes back.

1Connect— your Portkey admin key, used once, never stored
{{ pbErr }}
2Configs to bench— the guarded config, and an optional baseline for A/B
3What to fire— attack categories (English), through both lanes
Loading attack categories…
{{ pbPlanNote }}
{{ pbRunHint }}
{{ pbError }}
{{ pbProgTitle }}{{ pbProgCounts }} · {{ pbProgElapsed }}

Results

{{ pbTruncNote }}
{{ l.label }}
{{ l.blockPct }}blocked
{{ l.counts }}
latency p50 {{ l.p50 }} · p90 {{ l.p90 }} · p99 {{ l.p99 }}
Attack categoryBlock rateVerdicts · pass · deny · err
{{ r.caret }}{{ r.label }}{{ r.rate }}{{ r.counts }}
{{ pbDrillTitle }} — sent traffic & gateway response
{{ d.verdict }}
{{ d.promptShort }}
{{ d.meta }}
{{ pbDrillNote }}
Testing · Portkey

Portkey Workbench

A Postman-style console for your Portkey gateway. Compose any request — method, URL, headers, query params, raw body — fire it live, and inspect the raw response, with the served model, token usage, and guardrail checks called out. Your key stays in the headers you set, used per call, never stored.

Portkey {{ ptConfigsHint }}
{{ ptErr }}
Sending the request through the gateway…
{{ ptStatusText }} {{ ptRespLatency }} ms · {{ ptRespSize }}
{{ ptRespErr }}
{{ ptRespBodyText }}
{{ hh.k }}{{ hh.v }}
Served by {{ ptFacetServed }}
Usage: {{ ptFacetUsage }} Cost: {{ ptFacetCost }}
Policy / guardrail checks
{{ c.verdict }}{{ c.label }}{{ c.phase }}
{{ ptFacetPolicyNote }}
Reply
{{ ptFacetReply }}
This response isn’t a chat completion, so Portkey’s served-model / usage / guardrail facets don’t apply. See the Body and Headers tabs for the raw result.
Equivalent curl — secrets redacted
{{ ptCurl }}
Migration · Portkey

Migrate a gateway → Portkey

Bring a LiteLLM or Kong AI Gateway config into Portkey. ENES translates it into a Portkey Config plus a dependency-ordered create-plan — and, above all, an honest report of what maps cleanly, what’s approximate, and what has no Portkey equivalent. Nothing is written to Portkey and no secret is read — credentials become placeholders you fill in at push time.

LiteLLM — bring your config.yaml

It’s the file you start the proxy with — you almost certainly already have it:

litellm --config config.yaml     # or the CONFIG_FILE_PATH env var

Running in a container or cluster? Read it straight out:

docker exec <container> cat /app/config.yaml
kubectl get configmap <litellm-config> -o yaml   # on Kubernetes
Manage LiteLLM from its Admin UI? Then it’s database-backed — your models, keys, teams and budgets live in Postgres, not the file, and there is no “export config.yaml” button. The config.yaml it booted from still migrates your routing, caching, retry and guardrail settings — and the Report below flags the database-only pieces as gaps so nothing is silently dropped.
Kong AI Gateway — bring your kong.yml

Export the declarative config with decK — this works for self-managed Kong and Konnect alike:

deck gateway dump -o kong.yml        # older decK: deck dump

Or just use the kong.yml you already deploy from.

Source
Try a sample:
{{ mgErr }}
Gateway

{{ mgLiveIntro }}

{{ mgConnectHint }}

{{ mgUploadHint }}

{{ mgErr }}
Detected source: {{ mgDetectedLabel }}
{{ mgClean }} clean {{ mgApprox }} approximate {{ mgGaps }} gaps
{{ iv.count }}{{ iv.label }}
Approximate — mapped, with something lost
{{ a.item }}{{ a.source }}
{{ a.lost }}
Gaps — no Portkey equivalent, flagged not faked
{{ g.item }}{{ g.source }}
{{ g.why }}
→ {{ g.recommendation }}
Clean — faithful 1:1
{{ c.item }}→ {{ c.maps_to }}
Heads up
• {{ w }}
Config {{ mgCfgName }} · slug {{ mgCfgSlug }}
{{ mgCfgText }}

What ENES would create in Portkey, in dependency order. Nothing here runs yet — the push stage will, and the Portkey target (base URL + admin key) is entered then, per run, never hardcoded.

{{ p.order }} {{ p.kind }}
{{ p.name }}
{{ p.detail }}
{{ p.endpoint }}
Manual worklist — no create API (or unconfirmed on tenant)
{{ w.item }}
{{ w.why }}
→ {{ w.action }}

Push this migration into a Portkey tenant you own. The target — base URL + Admin API key — is entered here, used once per call, and never stored. ENES diffs against what already exists (idempotent by name/slug); nothing is created until you press Apply.

Push target
{{ mgPushErr }}
{{ mgPushSummaryLabel }}
Secrets to supply — credentials ENES never carries
{{ o.kind }}
{{ o.name }}
{{ o.error }}
{{ o.statusLabel }}
New API keys — shown once, copy & store securely
{{ k.name }}{{ k.value }}
Koi · Agentic endpoint security

Fleet posture board

Pull your live Koi fleet — every enrolled device and the agentic surface on it (extensions, MCPs, skills, packages) — into one board, each item risk-scored critical → low. Read-only.

1Connect— a Koi API key (Bearer), used once, never stored
{{ koErr }}
{{ t.label }}
{{ t.value }}
{{ t.sub }}
{{ koTruncNote }}
Devices
Wings finding catalog — what a risk level means
{{ f.band }}{{ f.name }}{{ f.desc }}
HostnameOSStatusLast userLast seen
{{ d.hostname }}{{ d.osLabel }}{{ d.status }}{{ d.user }}{{ d.when }}
{{ koSelTitle }}
{{ koSelSub }}
Reading the device inventory…
{{ koInvErr }}
{{ s.label }}
{{ i.risk }}
{{ i.name }} · {{ i.publisher }}
{{ i.meta }}
{{ koInvNote }}
Prisma AIRS · Model scanning

Scan a Hugging Face model

Paste a Hugging Face model repo — or several — and Prisma AIRS Model Scanning checks each one for supply-chain threats (unsafe pickles, embedded executables, and more) under our scanning policy, then hands you a go / no-go verdict. Nothing to set up: scanning runs on our tenant, so there are no keys or logins for you to manage.

How this works
1 · Paste the repo
One or more public Hugging Face model URLs — one per line.
2 · We scan & score
Each model is fetched and scanned live under our policy; a failed rule blocks it. A model still scanning at the time budget is reported as pending, never as passed.
How this works
1 · Upload the model
Pick your model file(s) — small demo models. We stage them in a private, auto-expiring bucket.
2 · We scan & score
A worker runs the real Prisma AIRS Model Security SDK on the files under our policy, then shows the same verdict — with any offending files named.
Scanning as
Hugging Face model URLs — one per line, up to {{ msCap }} Browse models on Hugging Face ↗
{{ msManifestCount }}
Must be a security group in {{ msPersonaLabel }}’s tenant — we look it up before scanning.
Model file(s)
{{ f.name }}{{ f.size }}
{{ msRunErr }}
{{ msProgress }}
{{ msVerdictLabel }}{{ msVerdictHead }}
{{ msVerdictSub }}
{{ t.label }}
{{ t.value }}
Why models blocked — failing rules across the manifest
{{ r.rule_name }}{{ r.count }}
Scanned models
{{ r.name }}
{{ r.metaLine }}
{{ r.outcome }}
No threats found — every check passed.
Failing checks
{{ f.name }}{{ f.countText }}
Blocked files
{{ bf.file }}
{{ bf.reasonsText }}
{{ r.errText }}
{{ r.rawJson }}
Portkey · AI gateway

Size a self-hosted gateway

Portkey publishes no sizing table — so this measures the real per-pod RPS ceiling from the gateway's /metrics under load (or you supply it), then computes replicas, CPU/memory, nodes, log storage, and a latency budget. Every number is tagged by where it came from.

How to size — read this first
Sizing a stateless gateway is one question: how many pods keep your busiest second under your latency promise, with room to spare? Three steps:
1 · Describe your load — your peak requests/second and the latency you promise (p95 SLO).
2 · Pin one pod's ceiling — the RPS a single gateway pod handles before it slows past your SLO. Measure it against a running gateway, or supply a benchmarked number. It's the only figure that can't be guessed — everything scales from it.
3 · Read the topology — ENES divides your peak by that ceiling (keeping autoscale headroom) → replicas, CPU/memory, nodes, log storage, and a latency budget.
The resource boxes below are pre-filled with sensible field defaults — edit them only if your platform team runs different pod/node standards.
1Workload
Requests/second at your busiest minute — not the average. Read it off your gateway's traffic graph, or estimate: daily requests ÷ 86,400 × 3–5 (peak-to-average factor).
Your latency promise: 95% of requests must finish under this. Use your product/SLA target — e.g. 800 ms for a chat experience.
How long you keep request logs in the self-hosted control plane (compliance / debugging). Only drives the log-storage estimate below.
overheadms
Turn on if the AIRS scan runs in-line on every request. Overhead = milliseconds the scan adds — measure it (the bench task does this), or ~100–200 ms typical. It counts against your p95 SLO in the latency budget below.
Gateway pod
Pod vCPU
CPU reserved per gateway pod. 0.5 is a fine start — raise only if pods get CPU-throttled.
Pod memory (GiB)
Memory reserved per pod. 1 GiB to start; bump it if pods hit OOM.
Worker node
Node vCPU
Your K8s worker-node CPU. With pod vCPU, this sets how many pods fit per node.
Node memory (GiB)
The other limit on pods-per-node — whichever runs out first (CPU or memory) wins.
Scaling
Min replicas
Never run fewer than this — 2 keeps you serving if one pod dies.
Autoscale target %
Provision so peak lands at this utilisation — 60 leaves 40% headroom for spikes.
Storage & latency
Bytes / log
Avg size of one logged request+response. Drives the log-storage estimate; ~5 KB typical, more for big prompts.
Gateway ms
The gateway's own time (auth, routing, cache) excluding the LLM. From /metrics, or ~10–20 ms.
These are field-reference starting points — not official Portkey figures. Leave them unless your platform team runs different pod/node standards.
2Per-pod capacity— the one number I won't invent
The make-or-break number: how many requests/second one gateway pod sustains before its p95 crosses your SLO. Have a benchmark already? Supply it. Don't? Measure it live against a running gateway. Everything else scales from this one figure.
What it is: the highest sustained requests/second one gateway pod handles while p95 stays under your SLO — the point just before it saturates (latency climbs, Node's event loop lags). How to get it: load-test a single isolated pod, ramping RPS until p95 breaks your SLO — the last good rate is the ceiling. There's no universal number: it swings with payload size, whether the AIRS guardrail is inline, and streaming — so measure it or reuse a real benchmark. No number handy? Measure it live runs exactly that ramp for you.
{{ szErr }}
Point ENES at a reachable gateway (staging, or a prod instance ENES can hit — a firewalled prod gateway won't be). It needs three things: the /metrics URL (Prometheus endpoint, usually :8787/metrics), the base URL probe traffic hits (:8787/v1), and a config id routing to a cheap model so calls actually flow.
Fires real requests through the gateway (LLM cost) and reads /metrics each step, ramping until p95 crosses your SLO, event-loop lag climbs, or errors rise. Air-gapped gateway? Run the probe locally and use Supply it.
{{ szMeasureErr }}
TargetAchievedp95Loop lagMem
{{ s.target }}{{ s.achieved }}{{ s.p95 }}{{ s.lag }}{{ s.mem }}
{{ szCeilingNote }}

Recommended topology

{{ c.label }}
{{ c.value }}
{{ c.tag.label }}
{{ r.label }}{{ r.value }}{{ r.tag.label }}
Pod request is the CPU/memory reserved per pod — it just echoes the editable Pod vCPU / Pod GiB in Reference defaults above, so raise it there if your pods need more. But a bigger pod won't lift the RPS ceiling on its own: the gateway is single-threaded, so you serve more load with more replicas, not fatter pods (unless you measure a higher ceiling on the bigger pod and supply it). Effective / pod is the ceiling derated to your autoscale target — the number peak is actually divided by, leaving spike headroom. Log store is an upper bound: it assumes peak RPS every second for the whole retention window, so real usage runs well below it.
Latency budget{{ szLatBudget }} / {{ szLatSlo }} SLO
{{ szLatDetail }} · headroom {{ szLatHeadroom }}
This is fixed overhead before the model responds (gateway + guardrail). The LLM's own latency uses whatever's left under your SLO — if this bar is already near full, the model has no room.
⚠ {{ w }}
■ Measured■ Supplied■ Reference■ Estimate
Disconnect tenant?

{{ disconnectLabel }}” will be removed and its stored credentials destroyed. You can reconnect it later.

Rename tenant