> ## Documentation Index
> Fetch the complete documentation index at: https://docs.inviolet.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Five steps, five minutes — from zero to an agent calling a real tool through Inviolet, with the verdict in the live decision feed.

Five steps. Five minutes. By the end you'll have an agent calling a real tool
through Inviolet, with the verdict streaming into the live decision feed.

<Note>
  Want to **watch before you enforce**? You can install the SDK and observe
  every tool call in the decision feed without minting mandates or blocking
  anything — then turn on enforcement once you've seen the traffic. See
  [Generalize from observation](/guides/generalize-from-observation).
</Note>

## Prerequisites

* An Inviolet workspace ([sign up free](https://app.inviolet.ai/sign-up))
* Node 20+ (or any language — see the [REST flow](#4-mint-a-mandate-guard-a-tool-call) for non-Node stacks)
* Five minutes

## 1. Sign up + get an API key

Sign up at [app.inviolet.ai/sign-up](https://app.inviolet.ai/sign-up). On first
login you'll see the dashboard's onboarding panel; pick a scenario (AI-native
app dev, AI-assisted workflows, or data governance).

Open [Developer → API Keys](https://app.inviolet.ai/developer/api-keys) and
create a key. Save it as `INVIOLET_API_KEY` in your env.

## 2. Install the SDK

```bash theme={"dark"}
npm install @inviolet/agent-sdk-core
```

Pick a framework wrapper if your agent uses one — they all delegate to
`@inviolet/agent-sdk-core` under the hood, and they all expose the same
`Inviolet` client:

* [`@inviolet/agent-sdk-anthropic`](/sdks/anthropic)
* [`@inviolet/agent-sdk-openai`](/sdks/openai)
* [`@inviolet/agent-sdk-fetch`](/sdks/fetch)
* [`@inviolet/agent-sdk-langchain`](/sdks/langchain)
* [`@inviolet/agent-sdk-llamaindex`](/sdks/llamaindex)
* [`@inviolet/agent-sdk-mcp-client`](/sdks/mcp-client)

## 3. Create an intent card

Open [Gallery → Intents](https://app.inviolet.ai/gallery) and click *New intent
card*. Name your purpose, scope the operations + resources, and set a default
response strategy (start with `deny`; promote to `allow_with_redact` or `defer`
later).

Example for a customer-support copilot:

```json theme={"dark"}
{
  "purpose_id": "customer_support_lookup",
  "allowed_actions": [
    { "operation": "postgres.select", "resource_glob": "contacts.*" }
  ],
  "scope": {
    "operations": ["postgres.select"],
    "resources": ["contacts.first_name", "contacts.last_name", "contacts.email"]
  },
  "default_ttl_seconds": 300,
  "max_ttl_seconds": 3600,
  "on_action_outside_scope": "deny"
}
```

See [Intent cards](/concepts/intent-cards) for the full manifest shape.

## 4. Mint a mandate + guard a tool call

Mint one [mandate](/concepts/mandates) at the start of a session, then guard
every tool call against it.

<CodeGroup>
  ```ts Node theme={"dark"}
  import { Inviolet } from '@inviolet/agent-sdk-core'

  const inviolet = new Inviolet({
    gatewayUrl: process.env.INVIOLET_GATEWAY_URL!,
    apiKey: process.env.INVIOLET_API_KEY!,
    agentId: 'support-copilot',
  })

  // 1) Mint a mandate at the start of a session.
  const mandate = await inviolet.mintMandate({
    intentId: 'intents:customer_support_lookup',
    actor: 'alice@example.com',
    requestedScope: {
      operations: ['postgres.select'],
      resources: ['contacts.first_name', 'contacts.last_name'],
    },
    audience: 'postgres-prod',
  })

  // 2) Guard every tool call against the mandate.
  const verdict = await inviolet.guard({
    mandateJwt: mandate.credential,
    surface: 'sdk',
    operation: 'postgres.select',
    arguments: { table: 'contacts', id: 42 },
    audience: 'postgres-prod',
  })

  if (!verdict.allowed) {
    if (verdict.action === 'request_approval') {
      /* the gateway has queued an approval — poll or render in your UI */
    } else if (verdict.action === 'reroute') {
      /* the intent card defines a Violet-tier handler — fall back */
    } else {
      throw new Error(verdict.reason ?? 'Denied by Inviolet')
    }
  }

  // 3) Proceed with the actual tool call.
  const rows = await db.query(
    'SELECT first_name, last_name FROM contacts WHERE id = $1',
    [42],
  )
  ```

  ```python Python (REST) theme={"dark"}
  import os, httpx

  GATEWAY = os.environ["INVIOLET_GATEWAY_URL"]
  HEADERS = {"authorization": f"Bearer {os.environ['INVIOLET_API_KEY']}"}

  # 1) Mint a mandate.
  mandate = httpx.post(f"{GATEWAY}/v1/mandate/dispense", headers=HEADERS, json={
      "actor": "alice@example.com",
      "intent_id": "intents:customer_support_lookup",
      "requested_scope": {
          "operations": ["postgres.select"],
          "resources": ["contacts.first_name", "contacts.last_name"],
      },
      "audience": "postgres-prod",
  }).json()

  # 2) Guard a tool call against the mandate.
  verdict = httpx.post(
      f"{GATEWAY}/v1/mcp-proxy/call",
      headers={**HEADERS, "x-inviolet-mandate": mandate["credential"]},
      json={
          "action": {
              "surface": "sdk",
              "operation": "postgres.select",
              "arguments": {"table": "contacts", "id": 42},
          },
          "audience": "postgres-prod",
      },
  ).json()

  if not verdict["kind"].startswith("allow"):
      raise RuntimeError(verdict.get("message", "Denied by Inviolet"))
  ```
</CodeGroup>

<Note>
  There is no first-party Python package — the Python path calls the gateway's
  REST API directly. See the [REST reference](/sdks/rest) for every field.
</Note>

## 5. Watch it land in the dashboard

Open [app.inviolet.ai/dashboard](https://app.inviolet.ai/dashboard). Within
seconds you'll see your call in the [Decision Feed](/concepts/decision-feed)
with the full forensic chain — prompt → mandate → tool call → outcome — plus the
cascade's reasoning trail under *"Why was this picked?"*.

## What's next

* Read [The 5 Principles](/concepts/principles) to understand the doctrine.
* Set up [credential brokering](/concepts/credential-broker) so the agent never
  holds the real Postgres password.
* Promote your intent card from `deny` → `allow_with_redact` after a week of
  shadow-mode observation.
