Ecosystem

shapes CLI

Grant-constrained execution layer β€” run any CLI through structured permissions.

@openape/shapes

Shapes is the execution layer for agents. It wraps existing CLI tools and ensures every command runs within the boundaries set by grants. Instead of giving agents blanket access to kubectl or aws, Shapes maps each command to a structured permission and checks it against the agent's approved grants.

How It Works

Agent: "gh repo delete myorg/old-repo"
         ↓
Shapes: Load adapter for "gh"
         ↓
Parser: Match operation "repo.delete"
         ↓
Resolver: Build permission "gh:repo.delete(owner=myorg,name=old-repo)"
         ↓
Grant check: Does a valid grant cover this?
  β†’ Yes β†’ Execute command
  β†’ No  β†’ Request grant, wait for human approval

Installation

npm install -g @openape/shapes

Quick Start

# See what permissions a command requires (without executing)
shapes explain -- gh repo list myorg
# β†’ gh:repo.list (risk: low) β€” List repositories for owner myorg

# Request a grant and execute
shapes request --idp https://id.example.com --approval once -- gh issue create --repo myorg/app --title "Bug"
# β†’ Requests grant... waiting for approval... approved! Executing.

# Execute with a pre-approved grant token
shapes --grant <jwt> -- kubectl get pods -n production

The Shapes Registry

The Shapes Registry is the catalog of available adapters. It defines which CLI tools can be wrapped and how their commands map to permissions.

Registry Structure

The registry is a GitHub repository with TOML adapter definitions:

shapes-registry/
β”œβ”€β”€ registry.json          # Generated index (auto-built)
β”œβ”€β”€ adapters/
β”‚   β”œβ”€β”€ gh/
β”‚   β”‚   β”œβ”€β”€ adapter.toml   # Operation definitions
β”‚   β”‚   β”œβ”€β”€ meta.json      # Metadata
β”‚   β”‚   └── README.md
β”‚   β”œβ”€β”€ kubectl/
β”‚   β”œβ”€β”€ az/
β”‚   β”œβ”€β”€ exo/
β”‚   β”œβ”€β”€ o365mail/          # 20 operations for Outlook mail
β”‚   β”œβ”€β”€ ls/
β”‚   β”œβ”€β”€ cat/
β”‚   β”œβ”€β”€ chmod/
β”‚   └── ...

Discovering and Installing Adapters

# Search the registry
shapes adapter search github
# β†’ gh β€” GitHub CLI (devtools)

# Install an adapter
shapes adapter install gh

# List installed adapters
shapes adapter list

# Update all adapters
shapes adapter update

# Verify adapter integrity (SHA-256 digest)
shapes adapter verify gh

Adapters are cached locally at ~/.openape/shapes/adapters/. The registry is fetched from GitHub and cached for 1 hour.

Adapter Resolution Order

When Shapes loads an adapter, it searches in this order:

  1. Project-local: .openape/shapes/adapters/{id}.toml
  2. User home: ~/.openape/shapes/adapters/{id}.toml
  3. System: /etc/openape/shapes/adapters/
  4. Bundled: node_modules/@openape/shapes/adapters/
  5. Fallback: scan all directories for matching executable name

Adapter Format

Each adapter is a TOML file that maps CLI commands to operations:

schema = "openape-shapes/v1"

[cli]
id = "gh"
executable = "gh"
version = "1"

[[operation]]
id = "repo.list"
command = ["repo", "list"]
positionals = ["owner"]
display = "List repositories for owner {owner}"
action = "list"
risk = "low"
resource_chain = ["owner:login={owner}", "repo:*"]

[[operation]]
id = "issue.create"
command = ["issue", "create"]
required_options = ["repo", "title"]
display = "Create issue in {repo}: {title}"
action = "create"
risk = "medium"
resource_chain = ["repo:owner={repo|owner},name={repo|name}", "issue:*"]

[[operation]]
id = "repo.delete"
command = ["repo", "delete"]
positionals = ["repo"]
display = "Delete repository {repo}"
action = "delete"
risk = "critical"
exact_command = true
resource_chain = ["repo:owner={repo|owner},name={repo|name}"]

Operation Fields

FieldRequiredDescription
idYesUnique operation ID (e.g., repo.list)
commandYesCommand prefix to match (e.g., ["repo", "list"])
positionalsNoPositional argument names
required_optionsNoRequired --option names
displayYesHuman-readable description with {binding} templates
actionYesAction type: read, list, create, edit, delete, send, draft
riskYesRisk level: low, medium, high, critical
resource_chainYesHierarchical resource selectors
exact_commandNoIf true, only exact argv match is allowed (for destructive operations)

Resource Chains

Resource chains describe what is being accessed, hierarchically:

owner:login=myorg β†’ repo:name=myapp β†’ issue:id=42

Format: resource[:selector1=value1,selector2=value2]

Bindings use {name} templates resolved from parsed arguments:

  • {owner} β€” from positional argument
  • {repo|owner} β€” extract owner part from owner/name format
  • {repo|name} β€” extract name part
  • * β€” wildcard (matches any)

Risk Levels

LevelWhen to useApproval behavior
lowRead-only, listing operationsMay auto-approve with always grants
mediumCreate, edit operationsTypically once or timed grants
highDelete, modify permissionsRequires explicit once grant
criticalDestructive, irreversibleRequires once grant + exact_command = true

Integration with grapes

grapes uses Shapes for structured capability requests:

# Command-based (parses the actual CLI command)
grapes request "gh issue create --repo myorg/app --title Bug" --audience shapes --wait

# Capability-based (specify resources and actions directly)
grapes request-capability gh \
  --resource repo \
  --action list \
  --selector owner.login=myorg \
  --approval timed --duration 1h

Digest Verification

Security is enforced through SHA-256 digest verification at multiple points:

  1. Installation: Downloaded adapter TOML must match the registry digest
  2. Grant request: The adapter digest is included in the grant request
  3. Execution: The runtime adapter digest must match the grant's digest

This ensures that an adapter cannot be tampered with between grant approval and command execution.

Writing a Custom Adapter

  1. Create a directory in the shapes-registry:
adapters/my-tool/
β”œβ”€β”€ adapter.toml    # Operation definitions
β”œβ”€β”€ meta.json       # Metadata for the registry
└── README.md       # Documentation
  1. Define metadata in meta.json:
{
  "id": "my-tool",
  "name": "My Tool",
  "description": "Grant-aware wrapper for my-tool CLI",
  "author": "your-org",
  "category": "devtools",
  "tags": ["ci", "deployment"],
  "executable": "my-tool",
  "min_shapes_version": "0.3.0"
}
  1. Define operations in adapter.toml following the TOML format above
  2. Submit a PR to the shapes-registry β€” the CI will validate the adapter format and compute the digest

CLI Reference

# Adapter management
shapes adapter search <query>       # Search registry
shapes adapter install <id>         # Install adapter
shapes adapter remove <id>          # Remove adapter
shapes adapter list [--remote]      # List adapters
shapes adapter info <id>            # Show adapter details
shapes adapter update [<id>]        # Update adapters
shapes adapter verify <id>          # Verify digest

# Execution
shapes explain -- <cli> [args...]   # Explain required permissions
shapes request -- <cli> [args...]   # Request grant + execute
shapes --grant <jwt> -- <cli> [args...]  # Execute with pre-approved grant