Skip to main content

What Is a Tool Manifest?

A tool manifest is a declarative mapping from tool names to permission levels for a specific connector. It tells Grantex exactly which permission is required to call each tool, so enforcement does not have to guess from tool name keywords.
{
  "connector": "salesforce",
  "version": "1.0.0",
  "description": "Salesforce CRM connector",
  "tools": {
    "create_lead": "write",
    "update_opportunity": "write",
    "query": "read",
    "create_task": "write",
    "get_account": "read",
    "list_opportunities": "read"
  }
}
When an agent calls create_lead, Grantex looks up the manifest, sees that create_lead requires write permission, and checks whether the agent’s grant token includes a scope that covers write on the salesforce connector.

The Permission Hierarchy

Grantex defines four permission levels in a strict hierarchy. Higher levels subsume all lower levels:
admin (level 3)
  └── delete (level 2)
       └── write (level 1)
            └── read (level 0)
LevelPermissionTypical Operations
0readQuery, list, get, search, fetch, check, download
1writeCreate, update, send, post, upload, apply
2deleteDelete, remove, void, terminate, revoke, cancel
3adminRun payroll, period close, force reset, purge

Coverage Rules

A scope grants access to all tools at or below its permission level:
Granted ScopeREAD ToolsWRITE ToolsDELETE ToolsADMIN Tools
tool:X:readAllowedDeniedDeniedDenied
tool:X:writeAllowedAllowedDeniedDenied
tool:X:deleteAllowedAllowedAllowedDenied
tool:X:adminAllowedAllowedAllowedAllowed
Example: An agent with tool:salesforce:write:* can call query (read) and create_lead (write) but cannot call delete_contact (delete) or run_period_close (admin).

Scope Format

Tool enforcement scopes follow the format:
tool:{connector}:{permission}:{resource}[:capped:{N}]
PartRequiredDescription
toolYesFixed prefix identifying this as a tool scope
connectorYesThe connector name (e.g., salesforce, s3, stripe)
permissionYesThe maximum permission level granted (read, write, delete, admin)
resourceYesThe resource pattern (* for all tools on this connector)
capped:NNoOptional spending cap per operation (e.g., capped:500)

Examples

ScopeMeaning
tool:salesforce:write:*Write access to all Salesforce tools (covers read + write)
tool:s3:read:*Read-only access to all S3 tools
tool:stripe:write:*:capped:500Write access to Stripe tools, capped at 500 per operation
tool:jira:admin:*Full admin access to all Jira tools
tool:okta:delete:*Delete access to all Okta tools (covers read + write + delete)

How enforce() Uses Manifests

When you call enforce(), Grantex performs these steps:
  1. Decode the JWT — extract scp (scopes), grnt/jti (grant ID), agt (agent DID)
  2. Look up the manifest — find the loaded manifest for the given connector
  3. Resolve the permission — look up the tool name in the manifest to get its required permission level
  4. Check coverage — determine if any scope in the token covers the required permission on this connector
  5. Check caps — if the scope is capped and an amount was provided, verify the amount is within the cap
  6. Return the resultallowed: true or allowed: false with a reason
result = grantex.enforce(
    grant_token=token,           # JWT with scp: ["tool:salesforce:write:*"]
    connector="salesforce",      # Look up salesforce manifest
    tool="delete_contact",       # Manifest says: delete permission required
)
# Token grants write, tool requires delete -> DENIED
# result.allowed = False
# result.reason = "write scope does not permit delete operations on salesforce"

Pre-Built vs Custom Manifests

Pre-Built Manifests

Grantex ships 54 pre-built manifests covering 340+ tools across five categories:
CategoryConnectorsToolsExamples
Finance1488Stripe, SAP, QuickBooks, NetSuite
HR856Darwinbox, Okta, DocuSign, Greenhouse
Marketing16107Salesforce, HubSpot, Mailchimp, Google Ads
Ops748Jira, Confluence, ServiceNow, Zendesk
Comms1167Gmail, Slack, GitHub, S3, Twilio
Import and load them directly:
from grantex.manifests.salesforce import manifest as sf
from grantex.manifests.stripe import manifest as stripe

grantex.load_manifests([sf, stripe])

Custom Manifests

For internal APIs, connectors Grantex does not ship, or extensions to pre-built connectors:
  • Inline — define in code with ToolManifest(...)
  • JSON file — load from disk with ToolManifest.from_file("./manifests/my-service.json")
  • Extend pre-built — add tools to an existing manifest with manifest.add_tool("new_tool", Permission.WRITE)
  • CLI inspect — browse and validate manifests with grantex manifest list and grantex manifest validate

Fail-Closed Default

If enforce() is called with a connector or tool that has no manifest loaded, the call is denied by default:
result = grantex.enforce(
    grant_token=token,
    connector="unknown-service",
    tool="do_something",
)
# result.allowed = False
# result.reason = "No manifest loaded for connector 'unknown-service'. Load a manifest first."
This fail-closed behavior ensures that agents cannot bypass enforcement by calling tools that were never declared. Every tool must have an explicit permission entry in a loaded manifest. For development and testing, you can switch to permissive mode:
grantex = Grantex(
    api_key=key,
    enforce_mode="strict",       # default -- deny unknown tools
    # enforce_mode="permissive", # dev only -- allow unknown tools with warning
)
Never use enforce_mode="permissive" in production. It defeats the purpose of scope enforcement.

JSON Manifest File Format

When storing manifests as files (for git, CI, or team sharing), use this JSON format:
{
  "connector": "inventory-service",
  "version": "1.0.0",
  "description": "Internal warehouse inventory API",
  "tools": {
    "get_stock_level": "read",
    "reserve_inventory": "write",
    "release_reservation": "write",
    "adjust_stock": "write",
    "force_stock_reset": "admin"
  }
}
FieldTypeRequiredDescription
connectorstringYesUnique connector identifier
versionstringNoSemantic version of the manifest (default "1.0.0")
descriptionstringNoHuman-readable description
toolsobjectYesMap of tool name to permission level ("read", "write", "delete", "admin")