Resources
Skills & Docs Revisions
Soul Skills are versioned ZIP bundles stored on Walrus and indexed on-chain by skill name and version index. Each skill has an independent revision history, and versions can be marked public or private.
On-Chain Structure
// Shared object — one per Soul
public struct SoulSkills has key {
id: UID,
soul_id: ID,
skills: Table<String, vector<SkillSlot>>,
skill_count: u64, // unique skill names
}
public struct SkillSlot has copy, drop, store {
blob_object_id: ID,
is_public: bool,
deleted: bool,
created_at_ms: u64,
}
// Walrus Blob stored as dynamic object field
public struct SkillBlobKey has copy, drop, store {
skill_name: String,
version_index: u64, // 0-based index into slot vector
}The skills table maps a skillName string to a vector of SkillSlot values. Each append pushes a new slot; the index into the vector is the versionIndex. Both are required to address a specific version.
ZIP-Only Upload
Skills must be uploaded as .zip archives. The upload validation layer enforces this before the Walrus upload occurs. Inside the ZIP, a SKILL.md file at the root is required.
---
name: my-skill-name # becomes the on-chain skillName key
version: 1.0.0 # human-readable version label
description: |
What this skill does.
---
# Skill content hereThe name field from the frontmatter becomes the skillName used as the table key on-chain. If the name already exists in the SoulSkillstable, the new version is appended to that skill's vector (versionIndex increments). If it is new, a fresh entry is created (versionIndex = 0).
Public vs Private Visibility
Each version is individually marked is_public at upload time. This controls whether Seal encryption is required to read the blob.
| Visibility | Access model |
|---|---|
| public | Walrus blob URL is returned directly. No Seal session required. Anyone can download. |
| private | Seal-encrypted. Requires owner wallet or active SCOPE_SKILLS SoulGrant. Client must build approval TX and run Seal decryption. |
Visibility is immutable after mint. To change visibility you must append a new version with the desired setting.
Soft Delete
The owner (or a holder of SCOPE_SKILLS grant) can call skills::delete_version_as_owner or delete_version_as_granted_agent. This sets deleted = true on the slot — it does not remove the slot from the vector or free the Walrus blob.
- The
versionIndexis preserved. Attempting to read a deleted version returns an error from both the Move approval functions and the API. - A
SkillVersionDeletedevent is emitted withskills_id,skill_name,version_index, anddeleted_by. - Re-deleting an already-deleted slot aborts with
ESkillVersionDeleted.
Skills Access API
GET /api/souls/[id]/skills/[skillName]/versions/[versionIndex]/access
// Public response
{
visibility: "public",
artifact: { walrusBlobUrl, walrusBlobId, blobObjectId }
}
// Private response
{
visibility: "private",
artifact: { walrusBlobUrl, walrusBlobId, blobObjectId },
accessPolicy: {
packageId, stateObjectId, skillsObjectId,
skillName, versionIndex,
moduleName: "skills" | "content_access",
functionName:
"seal_approve_private_read_owner"
| "seal_approve_private_read_granted_agent"
| "seal_approve_skill_allowlisted",
soulGrantObjectId: string | null,
accessListOnChainId?: string,
documentIdHex: string,
},
seal: { ... },
sealSidecar: { ... },
viewerAddress, accessKind, sessionTtlMin
}The client SDK function fetchSkillAccess in web/lib/soulidity/skill-access.ts handles this request and returns a typed SkillAccessResponse. For private versions, call loadDecryptedPrivateSkillVersion to run the full Seal decryption flow and receive the plaintext ZIP bytes.