Skip to main content
This walkthrough takes you from zero to a denied tool call landing in your dashboard. By the end you’ll have:
  • An enrollment token so your code can self-bootstrap.
  • An agent registered against your org with its own signed identity.
  • A policy denying delete_file published as a bundle.
  • An audit event in the dashboard for the denied call, with the full trace attached.
This page assumes you’ve already been onboarded onto Rubric and your operator gave you the API URL plus a dashboard URL. If you haven’t installed the SDK yet, do Installation first.

1. Issue an enrollment token

Open the dashboard, go to Enrollment in the sidebar, and click Create token. You’ll be given an enr_… string shown once — copy it immediately.
export AG_ENROLLMENT_TOKEN=enr_a9f3db48e559.zTYwPTZvvelFZ7IHXICT29jwO14UWUM1IcaAg7Ne7ts
export AG_AGENT_NAME=quickstart-bot
export AG_API_URL=https://api.your-rubric-url.example.com
Enrollment tokens are long-lived, org-scoped, and register-only — they cannot ship audit events or read bundles. The blast radius if leaked is bounded (“attacker can create new agent rows in this org”) and revocable per-token from the dashboard.

2. Install the SDK

pip install 'rubric-app[mcp]'
The [mcp] extra pulls in MCP. Use [langchain] or [claude-agent] for those frameworks. Without an extra you still get the core SDK — the adapters are just optional wrappers.

3. Bootstrap and decorate

quickstart.py
import rubric

# One-time bootstrap. Reads AG_ENROLLMENT_TOKEN + AG_AGENT_NAME + AG_API_URL from env.
rubric.init(agent_name="quickstart-bot")

@rubric.tool
def list_files(path: str) -> str:
    return f"(would list {path})"

@rubric.tool
def delete_file(path: str) -> str:
    return f"(would delete {path})"

with rubric.session("demo"):
    print("list:", list_files("/tmp"))
    try:
        print("delete:", delete_file("/tmp/foo"))
    except rubric.GovernanceDeniedError as e:
        print("delete blocked:", e)
Run it:
python quickstart.py
The agent shows up on the dashboard’s Agents page within a few seconds. The two calls won’t be evaluated yet — a fresh agent has no policies scoped to it, so its bundle is empty and everything default-allows.

4. Author a policy and scope it to your agent

In the dashboard, go to PoliciesNew policy. The form has three required sections:
  • Name / slug — call it deny-destructive-fs.
  • Applied to agents — pick quickstart-bot from the list. This is required at publish time. Empty scope means the policy applies to nobody.
  • YAML — paste this:
apiVersion: agent-governance.io/v1
kind: Policy
metadata:
  name: deny-destructive-fs
  description: Block any agent from removing files.
spec:
  defaultEffect: allow
  rules:
    - id: no-delete
      description: Deny delete_file calls
      effect: deny
      conditions:
        - field: tool_name
          operator: eq
          value: delete_file
Save the draft, then click Publish. Rubric rebuilds the per-agent bundle for quickstart-bot to include this policy. Within ~30 seconds the SDK’s bundle poller picks it up and the next delete_file(...) call raises GovernanceDeniedError.

5. Re-run and see the deny

python quickstart.py
Now the second call returns deny. In the dashboard’s Audit log, click the deny row — the trace drawer opens with the full conversation transcript. Insights shows the deny on the timeline.

What’s next

Wire up your real agent

Drop in the MCP, Claude Agent, or LangChain adapter — no manual evaluate calls.

Write better policies

Conditions, scope, dry-run, version pinning.

Attach traces

Pass a TraceContext so every audit row has the conversation behind it.

Turn on DLP

Block tool calls whose arguments contain secrets, PII, or PHI.