Skills Protocol — Full Specification (v0.1)
A minimal protocol for connecting LLM agents to Skills (instructions + code) and Blobs (large data) via a Skills Runtime with sandboxed code execution.
The protocol is JSON-RPC 2.0 over HTTP.
This specification includes:
- Explicit LLM tool-call interface
- Canonical Skills Protocol Guide skill
- Bootstrap tool load_skills_protocol_guide
- Appendix with recommended system prompt snippet
Core Concepts
Skill
A Skill is a versioned bundle containing:
skill.toml— machine-readable manifest (id, runtime, permissions, metadata)SKILL.md— instructions & examples for the LLMcode/— optional executable implementationresources/— optional supporting files (extra docs, schemas, etc.)
Skills come in two kinds:
- Action skills — have a runtime and can be executed
- Instruction skills — only provide context (no runtime)
Blob
A Blob is an opaque handle (blob:<id>) to large data (text, binary, JSON). Blobs live in the runtime's storage and can be mounted into sandboxes. Large documents, logs, CSVs, etc. should be represented as blobs rather than inline JSON. Skills and code operate on blobs without passing large data through the LLM.
Run
A Run is a single ephemeral sandbox execution:
- Either via
execute_skill— run a skill's entrypoint - Or via
run_code— run LLM-written code that can import skills
Each run has:
run_id— stable identifierstatus—"completed"or"failed"summary— short human-readable description- Optional
output,output_blobs,logs_preview, anderror
Skills Runtime
A Skills Runtime is a server implementing this spec. It:
- Stores Skills and Blobs
- Creates sandboxed execution environments
- Exposes a JSON-RPC 2.0 API
- Provides an LLM-visible tool surface
LLM Tool-Call Interface (Normative)
Runtimes MUST expose these tools to the LLM:
list_skills— enumerate available skillsdescribe_skill— retrieve skill manifest and documentationread_skill_file— read any file in a skill's directoryexecute_skill— run a skill's entrypointrun_code— execute LLM-written code with mounted skillscreate_blob— store large contentread_blob— retrieve blob previewsload_skills_protocol_guide— bootstrap instruction tool
These are the only LLM tools. Skills do not appear as native tools to the LLM.
Tool Schemas
The following schemas define the tool interface for LLMs. Runtimes SHOULD expose these in a format compatible with their LLM integration (e.g., OpenAI function calling, Anthropic tool use, etc.).
list_skills
{
"name": "list_skills",
"description": "Enumerate available skills, optionally filtering by namespace. Results are deterministically sorted.",
"parameters": {
"type": "object",
"properties": {
"namespace": {
"type": "string",
"description": "Optional namespace to filter skills (e.g., 'salesforce')"
},
"detail": {
"type": "string",
"enum": ["names", "summary"],
"default": "names",
"description": "Level of detail to return"
},
"limit": {
"type": "integer",
"default": 50,
"description": "Maximum number of results"
},
"cursor": {
"type": "string",
"description": "Pagination cursor from previous response"
}
}
}
}
describe_skill
{
"name": "describe_skill",
"description": "Retrieve a skill's manifest and documentation frontmatter.",
"parameters": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Skill name (e.g., 'salesforce.leads.sync')"
},
"version": {
"type": "string",
"description": "Skill version (omit for latest)"
},
"detail": {
"type": "string",
"enum": ["manifest", "summary", "full"],
"default": "summary",
"description": "Level of detail to return"
}
},
"required": ["name"]
}
}
read_skill_file
{
"name": "read_skill_file",
"description": "Read any file in a skill's directory (e.g., SKILL.md, extra docs, schemas).",
"parameters": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Skill name"
},
"version": {
"type": "string",
"description": "Skill version (omit for latest)"
},
"path": {
"type": "string",
"description": "Path to file within skill directory (e.g., 'SKILL.md')"
}
},
"required": ["name", "path"]
}
}
execute_skill
{
"name": "execute_skill",
"description": "Execute a skill's entrypoint in an ephemeral sandbox.",
"parameters": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Skill name"
},
"version": {
"type": "string",
"description": "Skill version (omit for latest)"
},
"args": {
"type": "object",
"description": "JSON-serializable arguments to pass to the skill"
},
"input_blobs": {
"type": "array",
"items": {"type": "string"},
"description": "Blob IDs to mount in the sandbox"
},
"timeout_ms": {
"type": "integer",
"description": "Execution timeout in milliseconds"
}
},
"required": ["name"]
}
}
run_code
{
"name": "run_code",
"description": "Execute LLM-written code in a sandbox with specified skills and blobs mounted.",
"parameters": {
"type": "object",
"properties": {
"language": {
"type": "string",
"enum": ["python"],
"description": "Programming language (MVP: python only)"
},
"code": {
"type": "string",
"description": "Source code to execute"
},
"entrypoint": {
"type": "string",
"default": "main",
"description": "Function name to call"
},
"args": {
"type": "object",
"description": "Arguments to pass to entrypoint function"
},
"mount_skills": {
"type": "array",
"items": {"type": "string"},
"description": "Skill names to mount in sandbox"
},
"input_blobs": {
"type": "array",
"items": {"type": "string"},
"description": "Blob IDs to mount in sandbox"
},
"limits": {
"type": "object",
"properties": {
"timeout_ms": {"type": "integer"}
},
"description": "Execution limits"
}
},
"required": ["language", "code"]
}
}
create_blob
{
"name": "create_blob",
"description": "Store large content as a blob and return its ID.",
"parameters": {
"type": "object",
"properties": {
"content": {
"type": "string",
"description": "Content to store"
},
"kind": {
"type": "string",
"description": "MIME type (e.g., 'text/plain', 'application/json')"
}
},
"required": ["content", "kind"]
}
}
read_blob
{
"name": "read_blob",
"description": "Retrieve a preview of blob content. Full reads discouraged for large blobs.",
"parameters": {
"type": "object",
"properties": {
"blob_id": {
"type": "string",
"description": "Blob identifier"
},
"mode": {
"type": "string",
"enum": ["sample_head", "sample_tail", "full"],
"default": "sample_head",
"description": "How to sample the blob"
},
"max_bytes": {
"type": "integer",
"default": 2000,
"description": "Maximum bytes to return"
}
},
"required": ["blob_id"]
}
}
load_skills_protocol_guide
{
"name": "load_skills_protocol_guide",
"description": "Load the Skills Protocol Guide to learn how to use these tools. Call this first if you haven't read the guide yet.",
"parameters": {
"type": "object",
"properties": {}
}
}
Python Client Example
Here's a minimal example of how an LLM agent would interact with a Skills Runtime using these tools:
import requests
class SkillsRuntimeClient:
def __init__(self, endpoint="http://localhost:8080/rpc"):
self.endpoint = endpoint
self.request_id = 0
def _call(self, method, params=None):
self.request_id += 1
payload = {
"jsonrpc": "2.0",
"id": str(self.request_id),
"method": method,
"params": params or {}
}
response = requests.post(self.endpoint, json=payload)
result = response.json()
if "error" in result:
raise Exception(f"RPC Error: {result['error']}")
return result["result"]
def list_skills(self, namespace=None, detail="names", limit=50):
return self._call("list_skills", {
"namespace": namespace,
"detail": detail,
"limit": limit
})
def describe_skill(self, name, version=None, detail="summary"):
params = {"name": name, "detail": detail}
if version:
params["version"] = version
return self._call("describe_skill", params)
def read_skill_file(self, name, path, version=None):
params = {"name": name, "path": path}
if version:
params["version"] = version
return self._call("read_skill_file", params)
def execute_skill(self, name, args=None, version=None,
input_blobs=None, timeout_ms=None):
params = {"name": name}
if version:
params["version"] = version
if args:
params["args"] = args
if input_blobs:
params["input_blobs"] = input_blobs
if timeout_ms:
params["timeout_ms"] = timeout_ms
return self._call("execute_skill", params)
def run_code(self, code, language="python", entrypoint="main",
args=None, mount_skills=None, input_blobs=None,
timeout_ms=None):
params = {
"language": language,
"code": code,
"entrypoint": entrypoint
}
if args:
params["args"] = args
if mount_skills:
params["mount_skills"] = mount_skills
if input_blobs:
params["input_blobs"] = input_blobs
if timeout_ms:
params["limits"] = {"timeout_ms": timeout_ms}
return self._call("run_code", params)
def create_blob(self, content, kind="text/plain"):
return self._call("create_blob", {
"content": content,
"kind": kind
})
def read_blob(self, blob_id, mode="sample_head", max_bytes=2000):
return self._call("read_blob", {
"blob_id": blob_id,
"mode": mode,
"max_bytes": max_bytes
})
def load_skills_protocol_guide(self):
return self._call("load_skills_protocol_guide", {})
# Example usage
client = SkillsRuntimeClient()
# 1. Load the protocol guide (first-time usage)
guide = client.load_skills_protocol_guide()
print(guide["content"])
# 2. Discover available skills
skills = client.list_skills(namespace="salesforce")
print(f"Found {len(skills['skills'])} Salesforce skills")
# 3. Inspect a specific skill
skill_info = client.describe_skill("salesforce.leads.sync")
print(f"Skill: {skill_info['skill']['manifest']['description']}")
# 4. Read full documentation
docs = client.read_skill_file("salesforce.leads.sync", "SKILL.md")
print(docs["content"])
# 5. Create a blob for large data
csv_data = "name,email,company\nJohn Doe,john@example.com,Acme Inc\n..."
blob = client.create_blob(csv_data, kind="text/csv")
print(f"Created blob: {blob['blob_id']}")
# 6. Execute the skill
result = client.execute_skill(
name="salesforce.leads.sync",
args={
"sheet_blob": blob["blob_id"],
"env": "prod"
},
input_blobs=[blob["blob_id"]]
)
if result["status"] == "completed":
print(f"Success: {result['summary']}")
print(f"Output: {result['output']}")
else:
print(f"Failed: {result['error']['message']}")
# 7. Run custom code that uses multiple skills
code = """
from skills.salesforce.leads.sync import sync_leads
from skills.gdrive.sheets.read import read_sheet
from runtime import blobs
def main(args):
# Read data from Google Sheets
sheet_data = read_sheet(args['sheet_url'])
# Convert to blob
blob_id = blobs.write_text(sheet_data)
# Sync to Salesforce
result = sync_leads(blob_id, env='prod')
return {
'synced': result['count'],
'errors': result['errors']
}
"""
result = client.run_code(
code=code,
mount_skills=["salesforce.leads.sync", "gdrive.sheets.read"],
args={"sheet_url": "https://docs.google.com/spreadsheets/d/..."}
)
print(f"Custom workflow result: {result['output']}")
This example demonstrates:
- Tool invocation via JSON-RPC
- Typical LLM agent workflow: discover → inspect → execute
- Both single-skill execution and multi-skill composition via
run_code - Blob handling for large data
Skill Artifacts
Skill Layout
On disk or in a registry, each skill has:
<skill_root>/
skill.toml
SKILL.md
code/ # optional
resources/ # optional
skill.toml (MVP Schema)
Minimal schema for v0.1:
# Required identifiers
name = "salesforce.leads.sync" # globally unique skill id
version = "0.1.0"
description = "Sync leads from a sheet blob into Salesforce."
kind = "action" # "action" | "instruction"
# Optional metadata
namespace = "salesforce" # for grouping / filtering
tags = ["crm", "leads", "sync"]
# Optional runtime (required for action skills)
[runtime]
language = "python" # MVP: "python" only
entrypoint = "code/main.py" # module path
export = "main" # function name
# Optional: informal input schema (for LLM & humans)
[inputs]
sheet_blob = { type = "blob", description = "Blob id of the source sheet" }
env = { type = "string", description = "Which Salesforce env" }
# Optional: permissions
[permissions]
network = ["https://*.salesforce.com"] # network allowlist
secrets = ["SALESFORCE_API_KEY"] # secret names the runtime may inject
Notes:
- Instruction skills can omit
[runtime]or setkind = "instruction" - For v0.1, runtimes MAY ignore
inputsandpermissionsbut SHOULD parse them
SKILL.md (MVP)
SKILL.md is markdown with YAML frontmatter at the top:
---
name: Salesforce Lead Sync
short_description: Sync leads from a sheet blob into Salesforce.
tags: [crm, leads, sync]
---
The body should briefly describe:
- What the skill does
- How to call it (expected arguments)
- One or two example tasks
JSON-RPC Conventions
The Skills Protocol uses JSON-RPC 2.0 over HTTP.
Success and Failure
There are two levels of error:
-
Protocol-level errors (JSON-RPC
error):- Invalid method name
- Invalid parameters
- Authorization failures
- Internal server errors unrelated to sandbox execution
-
Run-level failures (in-band inside
result):- Exceptions thrown by skill code
- Validation errors in skill code
- Timeouts or resource limits in the sandbox
Patterns:
// Successful RPC, run succeeded
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"status": "completed",
"...": "..."
}
}
// Successful RPC, run failed inside sandbox
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"status": "failed",
"error": {
"message": "Traceback...",
"type": "RuntimeError"
}
}
}
// Protocol-level error
{
"jsonrpc": "2.0",
"id": "1",
"error": {
"code": -32602,
"message": "Invalid params"
}
}
Runtimes MUST:
- Use top-level
erroronly for protocol/transport issues - Use
result.status = "failed"for sandbox / skill execution errors
Methods (MVP Surface)
All methods are invoked via JSON-RPC 2.0 at a single HTTP endpoint (e.g. /rpc).
Skill Discovery & Introspection
list_skills
Purpose: Enumerate available skills, optionally filtering by namespace.
Request:
{
"jsonrpc": "2.0",
"id": "1",
"method": "list_skills",
"params": {
"namespace": "salesforce", // optional, string
"detail": "names", // "names" | "summary"
"limit": 50, // optional, default 50
"cursor": null // optional, opaque pagination token
}
}
Response (detail = "names"):
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"skills": [
{
"name": "salesforce.leads.sync",
"version": "0.1.0",
"description": "Sync leads from a sheet blob into Salesforce.",
"namespace": "salesforce",
"kind": "action"
}
],
"next_cursor": null
}
}
Requirements:
- Results MUST be sorted deterministically (e.g.
(namespace, name, version DESC)) - Implementations MUST NOT perform semantic search here; this is a pure listing call
describe_skill
Purpose: Retrieve a skill's manifest and optional SKILL.md frontmatter/body.
Request:
{
"jsonrpc": "2.0",
"id": "2",
"method": "describe_skill",
"params": {
"name": "salesforce.leads.sync",
"version": "0.1.0", // optional, latest if omitted
"detail": "summary" // "manifest" | "summary" | "full"
}
}
Response (detail = "summary"):
{
"jsonrpc": "2.0",
"id": "2",
"result": {
"skill": {
"manifest": { /* parsed skill.toml */ },
"skill_md_frontmatter": { /* parsed YAML frontmatter */ }
}
}
}
If detail = "full", runtimes MAY include the full SKILL.md content inline, but are encouraged to keep responses small and rely on read_skill_file for large docs.
read_skill_file
Purpose: Read any file in a skill's directory (e.g. full SKILL.md, extra markdown, schemas).
Request:
{
"jsonrpc": "2.0",
"id": "3",
"method": "read_skill_file",
"params": {
"name": "salesforce.leads.sync",
"version": "0.1.0",
"path": "SKILL.md"
}
}
Response:
{
"jsonrpc": "2.0",
"id": "3",
"result": {
"content": "# Salesforce Lead Sync\n\n..."
}
}
Runtimes MUST restrict path to the skill's directory and reject paths that attempt to escape (e.g. ../).
Skill Execution
execute_skill
Purpose: Run a skill's entrypoint in an ephemeral sandbox.
Request:
{
"jsonrpc": "2.0",
"id": "4",
"method": "execute_skill",
"params": {
"name": "salesforce.leads.sync",
"version": "0.1.0", // optional, latest if omitted
"args": { // JSON-serializable args
"sheet_blob": "blob:sheet-123",
"env": "prod"
},
"input_blobs": [ // optional blob ids to mount
"blob:sheet-123"
],
"timeout_ms": 300000 // optional, implementation default if omitted
}
}
Response (success):
{
"jsonrpc": "2.0",
"id": "4",
"result": {
"status": "completed",
"run_id": "run_9f2a",
"summary": "Synced 742 leads (5 failed).",
"output": {
"updated_count": 742,
"failed_count": 5
},
"output_blobs": [
"blob:sync-log-42",
"blob:failed-rows-1"
],
"logs_preview": "Connected to Salesforce...\nSynced 742 leads...\n"
}
}
Response (run failed):
{
"jsonrpc": "2.0",
"id": "4",
"result": {
"status": "failed",
"run_id": "run_9f2a",
"summary": "Exception while syncing leads.",
"error": {
"type": "RuntimeError",
"message": "Traceback (most recent call last):\n..."
},
"logs_preview": "Starting sync...\nTraceback...\n"
}
}
Requirements:
outputMUST be kept small (e.g. < 4KB serialized). Larger data MUST be written to blobslogs_previewSHOULD be truncated (e.g. < 2KB)- Runtimes MUST terminate sandbox execution if
timeout_msor internal resource limits are exceeded
Agent-Written Code
run_code
Purpose: Run LLM-written code in a sandbox, with specified skills and blobs mounted.
Request:
{
"jsonrpc": "2.0",
"id": "5",
"method": "run_code",
"params": {
"language": "python",
"code": "from skills.salesforce.leads.sync import sync_leads\nfrom runtime import blobs\n\ndef main(args):\n ...",
"entrypoint": "main", // optional, default "main"
"args": {
"sheet_blob": "blob:sheet-123"
},
"mount_skills": [ // skill ids to mount
"salesforce.leads.sync",
"gdrive.sheets.read"
],
"input_blobs": [
"blob:sheet-123"
],
"limits": {
"timeout_ms": 300000 // optional
}
}
}
Response: Same structure as execute_skill:
{
"jsonrpc": "2.0",
"id": "5",
"result": {
"status": "completed",
"run_id": "run_abcd",
"summary": "Updated 142 pending orders, 3 failed.",
"output": {
"updated_count": 142,
"failed_count": 3
},
"output_blobs": [
"blob:sync-log-42"
],
"logs_preview": "Starting...\nUpdated 10...\n"
}
}
Runtimes MUST:
- Create a fresh sandbox for each
run_codecall - Mount requested skills and blobs (see Sandbox model below)
- Expose a small
runtimehelper library inside the sandbox
Blobs
create_blob
Purpose: Store arbitrary content as a blob and return its ID.
Request:
{
"jsonrpc": "2.0",
"id": "6",
"method": "create_blob",
"params": {
"content": "Discussed Q4 goals...\n[full transcript text]",
"kind": "text/plain" // or "application/json", etc.
}
}
Response:
{
"jsonrpc": "2.0",
"id": "6",
"result": {
"blob_id": "blob:transcript-abc123",
"size_bytes": 200000
}
}
read_blob
Purpose: Retrieve a small view of a blob. Full reads are discouraged for large blobs.
Request:
{
"jsonrpc": "2.0",
"id": "7",
"method": "read_blob",
"params": {
"blob_id": "blob:transcript-abc123",
"mode": "sample_head", // "sample_head" | "sample_tail" | "full"
"max_bytes": 2000
}
}
Response:
{
"jsonrpc": "2.0",
"id": "7",
"result": {
"content": "Discussed Q4 goals...\n[truncated]",
"truncated": true,
"kind": "text/plain"
}
}
Runtimes SHOULD:
- Support
sample_headandsample_tail - Treat
"full"as best-effort and MAY reject it for very large blobs
Bootstrap Instruction Tool
load_skills_protocol_guide
Purpose: Return the SKILL.md content of the canonical Skills Protocol Guide skill. This is a bootstrap instruction tool that teaches the LLM how to use the Skills Protocol.
Request:
{
"jsonrpc": "2.0",
"id": "8",
"method": "load_skills_protocol_guide",
"params": {}
}
Response:
{
"jsonrpc": "2.0",
"id": "8",
"result": {
"content": "# Skills Protocol Overview\n\nAvailable tools:\n\n1. `list_skills`\n..."
}
}
This method MUST return the content of the canonical skills.protocol.guide skill's SKILL.md file.
Creating Skills (Optional)
create_skill
Purpose: Register a new skill programmatically (e.g. written by an agent).
Request:
{
"jsonrpc": "2.0",
"id": "9",
"method": "create_skill",
"params": {
"manifest": { /* skill.toml parsed as JSON */ },
"skill_md": "# My New Skill\n\n...",
"files": [
{ "path": "code/main.py", "content": "def main(args):\n ..." },
{ "path": "resources/examples.md", "content": "Example usage..." }
]
}
}
Response:
{
"jsonrpc": "2.0",
"id": "9",
"result": {
"name": "user.julaiti.save_sheet_as_csv",
"version": "0.1.0"
}
}
Runtimes MUST:
- Validate that
pathvalues stay within the skill root - Either persist the skill immediately or return a protocol-level error
Canonical Instruction Skill: skills.protocol.guide
Every Skills Runtime MUST include this canonical instruction skill to bootstrap LLM understanding of the protocol.
skill.toml
name = "skills.protocol.guide"
version = "0.1.0"
description = "Intro to the Skills Protocol for LLMs."
kind = "instruction"
namespace = "skills.protocol"
tags = ["guide", "bootstrap"]
SKILL.md
---
name: Skills Protocol Guide
short_description: How to use the Skills Protocol tools.
---
# Skills Protocol Overview
Available tools:
1. `list_skills` — enumerate available skills
2. `describe_skill` — retrieve skill manifest and documentation
3. `read_skill_file` — read any file in a skill's directory
4. `execute_skill` — run a skill's entrypoint
5. `run_code` — execute LLM-written code with mounted skills
6. `create_blob` — store large content
7. `read_blob` — retrieve blob previews
8. `load_skills_protocol_guide` — bootstrap instruction tool (this guide)
## Recommended Workflow
1. **Discover skills**: Use `list_skills` to see what's available, optionally filtering by namespace
2. **Inspect documentation**: Use `describe_skill` and `read_skill_file` to understand how to use skills
3. **Run simple actions**: Use `execute_skill` for single-skill operations
4. **Write multi-step workflows**: Use `run_code` to compose multiple skills with custom logic
5. **Use blobs for large data**: Store and retrieve large content via `create_blob` and `read_blob`
## Best Practices
- Always use blobs for data larger than a few KB
- Keep `output` fields small; write large results to blobs
- Read skill documentation before executing
- Use deterministic skill discovery (no semantic search in `list_skills`)
Sandbox Execution Model (MVP)
For each execute_skill and run_code call, the runtime MUST:
Sandbox Creation
-
Create a sandbox
- Separate process or container
- Non-root user
- Enforce CPU, memory, and wall-clock time limits
-
Mount resources
- For each skill in
mount_skills(and the target skill forexecute_skill):- Mount the skill directory as
/skills/<name>/(read-only)
- Mount the skill directory as
- Create
/workspace/as a writable directory - Make blobs available:
- Either mount as
/blobs/<blob_id>files, and/or - Expose via helper functions in
runtime.blobs
- Either mount as
- For each skill in
-
Set environment
- Inject only secrets listed in
permissions.secretsfor the executing skill - Optionally restrict outbound network to
permissions.network
- Inject only secrets listed in
-
Execute
- For
execute_skill:- Import the skill's
runtime.entrypointmodule and callexport(args)
- Import the skill's
- For
run_code:- Save
codeas a temporary module, import it, and callentrypoint(args)
- Save
- For
-
Collect results
- Capture return value as
output(small JSON) - Capture stdout/stderr to build
logs_preview(truncated) - Any blobs created via runtime helper functions become
output_blobs
- Capture return value as
-
Tear down
- Destroy sandbox and all temporary files in
/workspace/
- Destroy sandbox and all temporary files in
In-Sandbox Helper Library (Python MVP)
Runtimes MUST provide a runtime package with at least:
# runtime/blobs.py
def read_text(blob_id: str) -> str: ...
def write_text(content: str) -> str: ...
def write_json(obj) -> str: ...
# runtime/log.py
def info(msg: str): ...
def error(msg: str): ...
These helpers:
- Call back to
create_blobunder the hood (or equivalent internal API) - Append to logs that feed into
logs_preview
Implementation Checklist (v0.1)
To implement a minimal but complete Skills Runtime:
Transport
- JSON-RPC 2.0 over HTTP at
/rpc
Storage
- Skills stored as directories with
skill.toml+SKILL.md - Blobs stored as files in a blob directory, named by random ids
Supported Methods
- MUST:
list_skills,describe_skill,read_skill_file - MUST:
execute_skill,run_code - MUST:
create_blob,read_blob - MUST:
load_skills_protocol_guide - SHOULD:
create_skill
Runtime
- MVP: Python-only skills (
runtime.language = "python") - Sandbox as:
- New process with restricted environment, or
- Container with resource limits
- Use the filesystem layout described in section 7
Safety
- Non-root execution
- No network by default; allowlist from
permissions.networkif implemented - No secrets by default; inject only those named in
permissions.secrets
Canonical Skill
- Include
skills.protocol.guideas described in section 6
Appendix A: Recommended System Prompt
When connecting an LLM to a Skills Runtime, include this snippet in the system prompt:
You are connected to a Skills Runtime using the Skills Protocol.
If you have not yet read the Skills Protocol Guide,
you MUST call the `load_skills_protocol_guide` tool before using
any other Skills Protocol tools.
After reading the guide, follow its workflow:
discover → inspect → run or write code → use blobs for large data.
Appendix B: Minimal Example
- User: "Sync these leads."
- LLM: upload CSV →
create_blob - LLM:
list_skills(namespace="salesforce") - LLM:
describe_skill→ inspect input format - LLM:
execute_skill - LLM: return summary + preview of failed rows