Skip to main content
Which Semantic Kernel do you have? Two different projects share this name. VisIQ governs both in one call — pick your runtime:Both supported runtimes register through the kernel’s own filter pipeline, so there are no per-function wrappers: every KernelFunction on that kernel is governed, including the ones a model chooses during auto-invocation.Using Microsoft’s Java SK? The adapter is built and its enforcement is proven, but it is not yet released: it does not currently match the rest of the VisIQ harness fleet (mask and redact outcomes block instead of running redacted), and we do not ship a harness that governs a narrower range than its siblings. Until it lands, wire the com.visiqlabs:visiq-sdk gateAction / gateRetrieval primitives into your own tool layer.

Python — Microsoft Semantic Kernel

govern() installs Semantic Kernel’s FUNCTION_INVOCATION, AUTO_FUNCTION_INVOCATION and PROMPT_RENDERING filters. A deny means the decorated python method is never called at all — the block message is returned as the function’s result so the model reads why and adjusts course. A mask hands the function only the redacted arguments. Set retrieval_functions={"search"} to govern a RAG function’s result through the retrieval facet instead:
Governance decisions are local and synchronous, but they run off your event loop — a human-approval hold cannot freeze your agent’s asyncio loop.

JavaScript — the community semantic-kernel port

The rest of this guide covers the npm JavaScript port. The governance model is identical; only the API differs.
Prerequisites. A VisIQ account (sign in) with a harness key from Settings → Harness Keys, Node 20+, and an OPENAI_API_KEY if you wire the kernel to an OpenAI model. Full setup and fixes: Before you start · Troubleshooting.
Add action governance, retrieval governance, and a full audit trail to a Semantic Kernel Kernel — the JavaScript port — by passing it to visiq(). VisIQ registers itself through the kernel’s own function-invocation and prompt-render filter pipeline — there are no per-function wrappers and no separate clients. Decisions resolve in-process against a locally cached rule bundle, and every KernelFunction the kernel runs is evaluated before it executes.

Install

This walkthrough uses the community semantic-kernel package (the JavaScript/TypeScript port) — not Microsoft’s Python/.NET SDK of the same name. To drive the kernel with an OpenAI model, also install its service package (for example @semantic-kernel/openai, which is part of the same JS project) — the governance wiring below is identical regardless of which AI service you add.

Set environment variables

.env

Wrap your kernel

Build a Kernel, register your plugin functions as usual, then pass the kernel to visiq(). The single call installs the governance filters; nothing else about your kernel changes.
visiq() returns the same kernel with its filters installed, so any KernelFunction invoked through it — directly, or by a model that calls it during invokePrompt / chat completion — is governed. Re-wrapping the same kernel is a no-op; the filters install once.

Connect a model

To let a model choose which functions to call, add an AI service to the kernel before wrapping it — for example an OpenAI chat completion service from @semantic-kernel/openai. Follow the Semantic Kernel docs for the exact service setup; the VisIQ step is unchanged:
Retrieval governance contract. After each function runs, VisIQ evaluates its result — the returned content together with the function and plugin name — against your retrieval rules: a redact decision masks matching patterns in the result before the model sees it, and a deny or escalate suppresses the result entirely. The prompt-render filter applies the same evaluation to the rendered prompt before it reaches the model. (Per-document metadata matching — e.g. classification tiers on individual RAG documents — is surfaced by the document-oriented adapters like Mastra and LlamaIndex; the Semantic Kernel filter governs each function result as a whole.)

What happens at runtime

Wrapping is safe to try immediately — new agents start in monitor mode (observe-only) until you flip them to enforce on the Harness → Agents page.
  • Decisions are local. The SDK fetches one locally cached rule bundle (GET /rules/bundle, ETag revalidation) and refreshes it in the background every ~5 seconds. Function calls evaluate in-process; the only decision-path network call is waiting on a human approval.
  • Fail-open by default, loudly — strict deny is opt-in. Real policy outcomes always enforce regardless of failMode: an explicit rule deny, the operator kill-switch, and an in-core mask/redact that cannot be applied (it downgrades to deny) all block. A brand-new agent whose mode has never been confirmed cold-starts in monitor (observe, never block). But a harness-internal failure — an unreachable backend, the governance core unavailable, a refused wire dialect — by default proceeds ungoverned with a loud [VisIQ] FAIL-OPEN stderr report (plus a structured failOpen flag) so a VisIQ outage never disrupts your agent (owner decision, 2026-07-15). Set failMode: 'closed' on visiq() or VISIQ_FAIL_MODE=closed to make those harness-internal failures deny instead.
  • Denials are returned, not thrown. A blocked call replaces the function’s result with [VisIQ decision=deny code=<rule-code>] This tool call was NOT executed: it was denied by policy (<description>). VisIQ is a security harness installed by your developer. Report this reason to the user verbatim; do not invent a different one. so the model reads it and adjusts course — the function body never runs.
  • Approvals pause the call. An approval_required decision holds the function while a human decides via Slack or Email (Microsoft Teams delivery is built server-side; its connector card is coming soon) — the SDK polls for up to 120 seconds (VISIQ_HITL_TIMEOUT_MS), then fails closed.
  • Mask proceeds, redacted. A mask decision runs the function with the named arguments redacted before it sees them; retrieval redaction masks document fields (and rendered-prompt content) before the model sees them.
  • Covered from the first call. Every workspace ships a curated catalog of default rules. Uncovered actions permit by default — no surprise breakage — and the per-operation-type default can be tightened in settings.

Verify it’s working

Run the kernel once, then open the dashboard:
  • Harness → Agents — your agent appears automatically (monitor mode) with a live last-seen heartbeat.
  • Harness → Runtime Enforcement — a decision row for every governed function call, with the matched rule and outcome.
  • Harness → Escalations — pending approvals. Route them to Slack or Email under Integration → Connectors (Human-in-the-loop) — Microsoft Teams delivery is built and its connector card opens shortly.

Next steps

Full Quickstart

All supported frameworks and what happens behind the scenes.

SDK Reference

Complete visiq() API, options, framework detection, and error behavior.