Semantic Skills
Semantic Skills extend Mayros agents with graph-aware capabilities. Each skill declares its permissions, assertions, and queries in a SKILL.md manifest. Skills run inside a QuickJS WASM sandbox with namespace-scoped access to the Cortex knowledge graph.
SKILL.md manifest
Every semantic skill is defined by a SKILL.md file with YAML frontmatter:
yaml--- type: semantic semantic: version: 1 permissions: graph: [read, write] proofs: [request, verify] memory: [recall, remember] assertions: - predicate: "isVerified" requireProof: true queries: - predicate: "hasStatus" scope: namespace allowedTools: - skill_graph_query - skill_assert - hub_search maxQueries: 100 skillVersion: "1.0.0" dependencies: - slug: "verify-kyc" version: "^1.0.0" ---
Permission categories
| Category | Values | Controls |
|---|---|---|
graph | read, write | Access to graph queries and assertions |
proofs | request, verify, publish | ZK proof operations |
memory | recall, remember | Skill memory context |
Validation rules
- Assertions with
requireProof: trueneedproofs: [request] - Queries require
graph: [read] - Assertions require
graph: [write] maxQueriesmust be >= 1 if specifiedskillVersionmust be valid semver
Skill loading pipeline
The SkillLoader handles two execution modes:
Sandbox mode (default)
- Read
skill.tsorskill.jsfrom the skill directory - Run the static scanner (
scanSource) — reject if critical findings - Transpile TypeScript to JavaScript
- Create a QuickJS WASM sandbox with resource limits
- Evaluate the skill code inside the sandbox
- Inject
graphClientandloggeras host functions - Return a
SkillRuntimeproxy that bridges calls into the sandbox
Direct mode (development only)
Requires MAYROS_UNSAFE_DIRECT_LOAD=1 and sandboxEnabled: false. Uses native import() with a 5-second timeout. Not recommended for production.
Core tools
The plugin registers six agent tools, all gated by permissions:
| Tool | Required permission | Description |
|---|---|---|
skill_graph_query | graph:read | Query the semantic graph with namespace scoping |
skill_assert | graph:write | Publish an assertion with optional PoL proof |
skill_verify_assertion | graph:read, proofs:verify | Verify an assertion's proof |
skill_request_zk_proof | proofs:request | Request a zero-knowledge proof |
skill_verify_zk_proof | proofs:verify | Verify a zero-knowledge proof |
skill_memory_context | memory:recall | Retrieve skill-scoped memory context |
Enrichment pipeline
When a skill_graph_query executes, the active skill's onQuery handler can enrich results:
- Graph query returns raw triples from Cortex
SkillLoader.invokeQuery()calls the skill runtime'sonQuery- The skill returns
additionalContext(enrichment data) sanitizeEnrichment()validates the response:- Parses as JSON or plain text
- Strips prompt injection patterns
- Enforces depth and length limits
- Wraps in
<skill-enrichment type="data">tags
- Enrichment is appended to the tool response (capped at 4096 chars)
- A 2-second timeout (
Promise.race) prevents DoS via slow enrichment
Namespace isolation
All graph operations are forced to the skill's namespace prefix (${ns}:):
typescript// enforceNsPrefix ensures all queries are scoped: // scope: "agent" → subject = "${ns}:agent:${agentId}" // scope: "namespace" → subject = "${ns}:${subject}" // scope: "global" → subject = "${ns}:${subject}" (capped to own ns)
The sandbox graphClient also enforces namespace prefixes on createTriple, deleteTriple, listTriples, and patternQuery.
Rate limiting
A SkillRateLimiter uses a sliding 1-minute window per skill:
- Default: 60 calls per minute (configurable via
maxCallsPerMinute) - Applied to:
skill_graph_query,skill_assert,skill_verify_assertion - Exceeding the limit returns a rate-limited error response
Query and write limits
Two layers of query limiting:
- Per-skill: each skill has
maxQueries(from manifest or config default of 50) - Global cap:
maxGraphQueries * activeSkillCount
Write limits are enforced inside the QuickJS sandbox via checkWriteLimit() (default: 50 writes per session).
Hot-reload
When hotReload: true, file changes trigger:
- Build temporary maps (manifests, resolvers, engines)
- Validate all manifests
- Downgrade block: reject if
allowedToolswere removed - Log manifest diffs (changes to permissions, assertions, maxQueries)
- Atomic swap: clear active maps, replace with new
- Dispose old sandboxes
Configuration
typescript{ cortex: { host: "127.0.0.1", port: 19090, authToken?: string }, agentNamespace: "mayros", // RDF namespace prefix skillSandbox: { sandboxEnabled: true, // false requires MAYROS_UNSAFE_DIRECT_LOAD=1 memoryLimitBytes: 8388608, // 1MB–256MB (default: 8MB) maxStackSizeBytes: 524288, // 64KB–8MB (default: 512KB) executionTimeoutMs: 10000, // 100–60000 (default: 10s) maxCallsPerMinute: 60, // 1–1000 (default: 60) maxGraphQueries: 50, maxAssertions: 20, proofTimeoutMs: 5000, allowZkProofs: true }, verification: { requireSignature: true, polValidation: true, autoScan: true }, hotReload: false }
Related
- Skill Security — 18-layer security architecture
- Cortex — AIngle Cortex knowledge graph
- Knowledge Graph — graph storage and querying