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:
| Asset | SDK entry point | Outcome |
|---|---|---|
| Model | scope.client(...) | Returns a governed chat client |
| MCP server | scope.mcp.register(...) | Registers and binds an MCP server |
| CLI policy | scope.cli.allow(...) | Creates, activates, and binds a command policy |
| Skill | scope.skills.ingest(...) | Ingests and binds skill content |
| Connector | scope.connectors.register(...) | Publishes and binds a connector |
| Sandbox route | scope.sandbox.route(...) | Creates and binds a route |
| Knowledge base | scope.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.