Skip to main content

Scopes and assets

Status: Beta Companion docs: Concepts · Identity · MCP Gateway API

A scope gives related AI work one clear goal. Bind models and tools to that scope, then apply the goal and scope rules across all of them.

For example, a refund flow may use a model, a ticket tool, and a skill. They should share the same goal instead of copying it into each call.

Create a scope

name and goal are required:

from trinitite import Trinitite

tr = Trinitite()

refund = tr.scope(
"refund-flow",
goal="Resolve refund requests within policy",
)

print(refund.id)

The first scope call also prepares the default governance baseline when you have not set one. It does not change organization settings.

Add only the controls this scope needs:

refund = tr.scope(
"refund-flow",
goal="Resolve refund requests within policy",
policies=["our-refund-policy"],
frameworks=["soc2"],
strictness="high",
hitl_zones=["refunds > $500"],
masking=["pii_ssn", "pii_card"],
mode="enforce",
cost_center="customer-support",
tags={"team": "support"},
)

Fields you leave out inherit the wider baseline. This lets a team set shared safety once, then tighten one workflow where needed.

Bind a model

Use the scope's client:

client = refund.client(
"openai",
credential="cred_openai_prod",
)

response = client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": "Can order 4821 receive a refund?",
}
],
)

result = tr.result(response)
print(result.scope_id, result.verdict)

The scoped client sends the scope in both the governance envelope and X-Trinitite-Scope. It also sends the provider credential as X-Trinitite-Credential-Id.

Set raise_on_blocked=True when blocked output should raise instead of returning a block response:

client = refund.client(
"openai",
credential="cred_openai_prod",
raise_on_blocked=True,
)

Bind tools and knowledge

The scope handle has seven asset entry points:

AssetSDK entry pointOutcome
Modelscope.client(...)Returns a governed chat client
MCP serverscope.mcp.register(...)Registers and binds an MCP server
CLI policyscope.cli.allow(...)Creates, activates, and binds a command policy
Skillscope.skills.ingest(...)Ingests and binds skill content
Connectorscope.connectors.register(...)Publishes and binds a connector
Sandbox routescope.sandbox.route(...)Creates and binds a route
Knowledge basescope.rag.register(...)Registers and binds a knowledge base

Register an MCP server:

mcp_response = refund.mcp.register(
"ticket-system",
url="https://mcp.example.com/sse",
transport="sse",
auth_type="bearer",
credential_id="cred_ticket_system",
)

if not mcp_response.ok:
raise RuntimeError(mcp_response.body)

Create a CLI allowlist:

cli_response = refund.cli.allow(
["git status", "python scripts/check_refund.py"],
block=["rm", "sudo"],
name="refund-safe-commands",
strictness="strict",
)

if not cli_response.ok:
raise RuntimeError(cli_response.body)

Ingest a skill:

skill_response = refund.skills.ingest(
"# Refund rules\nApprove standard refunds under $500.",
name="refund-rules",
description="Rules used by the refund assistant",
format="markdown",
labels=["support", "refunds"],
)

if not skill_response.ok:
raise RuntimeError(skill_response.body)

Each helper creates the asset and then binds it to the scope. The bind step is best effort. Check memberships when setup must be exact:

memberships = refund.memberships()

if not memberships.ok:
raise RuntimeError(memberships.body)

for membership in memberships.body.get("memberships", []):
print(membership["asset_node_id"])

Inspect the scope

Use the read methods to see the assets and governance around one goal:

estate = refund.estate()
compliance = refund.compliance()
improvement = refund.improvement(window="30d", bucket="day")

if estate.ok:
print(estate.body.get("assets", []))
print(estate.body.get("guardians", []))

if compliance.ok:
print(compliance.body.get("compliance_pct", {}))

if improvement.ok:
print(improvement.body.get("trajectory", {}))

improvement(...) also accepts ISO 8601 from_dt and to_dt values. These are sent as from and to query parameters.

Change the Guardian binding

Bind an existing Guardian by ID or name:

response = refund.bind_guardian(
guardian="refund-guardian",
)

if not response.ok:
raise RuntimeError(response.body)

Clear the scope-specific binding to return to inherited baseline governance:

response = refund.unbind_guardian()

The goal still groups the assets. The baseline still applies.

Use an agent scope for autonomous work

tr.agent(...) creates the same kind of scope and adds identity settings:

support = tr.agent(
"support-bot",
goal="Resolve support tickets within policy",
identity="support-bot",
privilege_tier=2,
nhi_scopes=["tickets:read", "tickets:write"],
max_spawn_depth=3,
nhi_ttl=300,
)

support_client = support.client(
"openai",
credential="cred_openai_prod",
)

The goal helps the Guardian judge whether the AI action fits the job. The identity and permission settings limit who is acting and what it may do.

Archive a scope

Archive a scope when the workflow is retired:

response = refund.archive()

if not response.ok:
raise RuntimeError(response.body)

Archiving is a soft delete. The service keeps the scope record for its audit window and rejects new calls under it.

Where to go next

  • Identity: create and limit a non-human identity for an agent.
  • Result: handle the verdict produced by a scoped call.
  • CLI Firewall API: manage command controls in more detail.
  • Skills API: manage skill content and scan results.