Resource Sets
Resource Sets are named collections of resources that define what agents can access inside the sandbox.
What Are Resource Sets?
A resource set is a collection of:
- HTTP/HTTPS destinations - Which websites the agent can reach
- Host mounts - Which host directories to mount into the container
- Environment variables - Which env vars to pass from host to container
- Ports - Which TCP/UDP ports to allow (e.g., SSH)
- Remote calls - Which host commands can be invoked from inside the sandbox
- Root commands - Commands to run as root before switching to the agent user
- Options - Container-level options like privileged mode
Why Resource Sets?
Different coding tasks need different resources:
| Task | Needs |
|---|---|
| Frontend development | npm registries, CDNs, Playwright |
| Backend development | Database connections, API testing |
| Deployment | Cloud APIs, SSH access, credentials |
| ML/AI development | Model downloads, GPU access |
Resource sets let you define these collections once and reuse them across your project.
Defining Resource Sets
Resource sets are defined in .shai/config.yaml:
1# .shai/config.yaml
2resources:
3 base-allowlist:
4 http:
5 - github.com
6 - npmjs.org
7 - pypi.org
8
9 frontend-dev:
10 http:
11 - cdn.jsdelivr.net
12 - unpkg.com
13 mounts:
14 - source: ${{ env.HOME }}/.cache/playwright
15 target: /home/${{ conf.TARGET_USER }}/.cache/playwright
16 mode: rw
17
18 deployment:
19 vars:
20 - source: AWS_ACCESS_KEY_ID
21 http:
22 - amazonaws.com
23 - s3.amazonaws.com
24 calls:
25 - name: deploy-staging
26 description: Deploy to staging environment
27 command: /usr/local/bin/deploy.sh
28 allowed-args: '^--env=staging$'Resource Set Components
HTTP/HTTPS Destinations
Allow agents to access specific websites:
1resources:
2 my-tools:
3 http:
4 - api.openai.com
5 - github.com
6 - registry.npmjs.orgHow it works:
- Shai configures a proxy (tinyproxy) and DNS filtering (dnsmasq)
- Only listed domains are accessible
- All other network traffic is blocked
github.com also allows api.github.com, raw.githubusercontent.com, etc.Host Mounts
Mount host directories into the container:
1resources:
2 cache-mount:
3 mounts:
4 - source: ${{ env.HOME }}/.cache/models
5 target: /home/${{ conf.TARGET_USER }}/.cache/models
6 mode: rw
7 - source: /etc/ssl/certs
8 target: /etc/ssl/certs
9 mode: roFields:
source: Absolute path on the hosttarget: Absolute path in the containermode:ro(read-only) orrw(read-write)
Use cases:
- Sharing package caches (npm, pip, cargo)
- Sharing model weights
- Sharing SSL certificates
- Sharing SSH keys (read-only!)
Environment Variables
Pass environment variables from host to container:
1resources:
2 api-keys:
3 vars:
4 - source: OPENAI_API_KEY
5 - source: ANTHROPIC_API_KEYSecurity note: Variables are mapped from host env, not hardcoded in config. This prevents credentials from being committed to git.
target field is optional. If omitted, the variable keeps the same name in the container. Only specify target when you need to rename the variable.Ports
Allow access to specific TCP/UDP ports:
1resources:
2 ssh-access:
3 ports:
4 - host: github.com
5 port: 22
6 - host: gitlab.com
7 port: 22Use cases:
- SSH to git servers
- Connecting to databases
- Accessing custom services
Remote Calls
Allow agents to invoke specific host commands:
1resources:
2 firmware-dev:
3 calls:
4 - name: flash-device
5 description: Flash firmware to connected device
6 command: /usr/local/bin/flash.sh
7 allowed-args: '^--port=/dev/tty\w+$'Fields:
name: Unique name for the calldescription: Human-readable descriptioncommand: Absolute path to host commandallowed-args: (Optional) Regex to filter arguments
Inside the sandbox:
1# Agent can invoke the call
2shai-remote flash-device --port=/dev/ttyUSB0See Selective Elevation for more details.
Root Commands
Run commands as root before switching to the agent user:
1resources:
2 docker-in-docker:
3 root-commands:
4 - "systemctl start docker"
5 options:
6 privileged: trueUse cases:
- Starting system services
- Loading kernel modules (
modprobe) - Setting up network interfaces
Options
Container-level options:
1resources:
2 gpu-access:
3 options:
4 privileged: trueAvailable options:
privileged: Run container in privileged mode (reduces isolation)
privileged: true sparingly! It significantly reduces container security.Template Expansion
Resource set fields support template variables:
1resources:
2 my-tools:
3 vars:
4 - source: MY_HOST_KEY # Host env var
5 target: API_KEY # Renamed in container
6 mounts:
7 - source: ${{ env.HOME }}/.cache
8 target: /home/${{ conf.TARGET_USER }}/.cache # Container user
9 mode: rwAvailable templates:
${{ env.NAME }}- Host environment variable${{ vars.NAME }}- Variable provided via--varflag${{ conf.TARGET_USER }}- The resolved target user (default:shai)${{ conf.WORKSPACE }}- The resolved workspace path (default:/src)
Using Resource Sets
Via Apply Rules
Resource sets are typically activated via apply rules:
1apply:
2 - path: ./
3 resources: [base-allowlist]
4
5 - path: frontend
6 resources: [frontend-dev, playwright]
7
8 - path: infrastructure
9 resources: [deployment, cloud-apis]When you run shai -rw frontend/components, Shai automatically applies base-allowlist, frontend-dev, and playwright.
Via CLI Flag
You can also opt into resource sets manually:
1shai -rw src --resource-set gpu-accessThis adds gpu-access to whatever resource sets are resolved via apply rules.
Resource Set Aggregation
When multiple rules match a path, their resource sets are aggregated (deduplicated):
1apply:
2 - path: ./
3 resources: [base-allowlist]
4
5 - path: backend
6 resources: [database-access]
7
8 - path: backend/payments
9 resources: [stripe-api]Running shai -rw backend/payments gets all three:
base-allowlist(from.)database-access(frombackend)stripe-api(frombackend/payments)
Best Practices
✅ Do
- Create focused, single-purpose resource sets
- Use descriptive names (
frontend-dev, nottools) - Map env vars instead of hardcoding credentials
- Document why each resource is needed (via comments)
- Start minimal and add resources as needed
❌ Don’t
- Create one giant “everything” resource set
- Hardcode secrets in the config
- Grant privileged mode unless absolutely necessary
- Mount sensitive directories as read-write
Examples
Frontend Development
1resources:
2 frontend-dev:
3 http:
4 - cdn.jsdelivr.net
5 - fonts.googleapis.com
6 - unpkg.com
7 mounts:
8 - source: ${{ env.HOME }}/.npm
9 target: /home/${{ conf.TARGET_USER }}/.npm
10 mode: rwPython ML Development
1resources:
2 ml-dev:
3 http:
4 - huggingface.co
5 - files.pythonhosted.org
6 mounts:
7 - source: ${{ env.HOME }}/.cache/huggingface
8 target: /home/${{ conf.TARGET_USER }}/.cache/huggingface
9 mode: rw
10 vars:
11 - source: HUGGINGFACE_TOKENKubernetes Deployment
1resources:
2 k8s-deploy:
3 vars:
4 - source: KUBECONFIG
5 mounts:
6 - source: ${{ env.HOME }}/.kube
7 target: /home/${{ conf.TARGET_USER }}/.kube
8 mode: ro
9 http:
10 - kubernetes.default.svc
11 calls:
12 - name: apply-manifests
13 description: Apply Kubernetes manifests
14 command: /usr/local/bin/kubectl-apply.sh
15 allowed-args: '^--namespace=\w+$'Next Steps
- Learn about Apply Rules to activate resource sets based on workspace paths
- See Configuration Reference for complete schema documentation
- Browse Examples for real-world resource set patterns