Resources
Soul content lives as typed slots under a single SoulContent object — one per Soul, bound once at mint. This page covers the three artifacts uploaded at mint time (soul.md, memory.md, skills.zip) plus persona assets (sprite / audio), how they map to KindRegistry kinds, and the addressing rules for every slot.
| Artifact | Kind | Name | Notes |
|---|---|---|---|
| soul.md | KIND_SOUL_DOC (0) | "soul" | Appended once at mint. Immutable forever — no delete or purge. |
| memory.md (founding) | KIND_MEMORY (1) | "default" | Single canonical name. Append-only log; soft delete & hard purge permitted. |
| skills.zip | KIND_SKILL (2) | from SKILL.md name: | Multi-name. Each name has its own version vector indexed by 0-based version_index. |
| sprite | KIND_SPRITE (3) | free-form | Persona art. Active binding selects the live sprite. Supports public / paid / grant reads. |
| audio | KIND_AUDIO (4) | free-form | Persona voice. Active binding + same read modes as sprite. |
See Kind Registry for the op-mask / read-mode-mask cells per kind and the rules for admin-registered custom kinds.
op_mask = 0 — no append, delete, or purge after mint. Read mode is OWNER | GRANT. The soul.md you ship is the soul.md forever.name = "default"; each append pushes a new version_index. Time order is encoded by index, not by timestamps.name front-matter field in SKILL.md becomes the on-chain key. Re-uploading the same name appends a new version_index; a new name creates a fresh slot starting at version_index = 0.content::set_active. The desktop companion reads from the active slot.READ_OWNER; seal_encrypted = true on every slot. Public reads use a different Seal approval entry, not bypass Seal.Every content slot is addressed by the triple (kind, name, version_index). This is the canonical addressing scheme across the on-chain layer, the access API, and DB mirrors. Legacy phase 1 addressing — separate SoulMemory / SoulSkills object IDs, timestamp_key, etc. — does not exist post-phase 2.
// Legacy Soul document route — fixed to (KIND_SOUL_DOC, "soul", 0)
GET /api/souls/[id]/access
// Content-slot access route
GET /api/souls/[id]/content/1/default/3/access
GET /api/souls/[id]/content/2/my-skill/0/access
GET /api/souls/[id]/content/3/idle/2/accessThese previews render the exact exported strings from @soulidity/sdk, so the docs stay aligned with the live uploader. Drop these into soul.md and memory.md verbatim and customize.
# Soul Character
## Core Truths
- What this Soul is here to do:
- Who it serves:
- The standard it refuses to compromise:
## Boundaries
- Hard constraints:
- Topics to avoid:
- Escalation rules:
## Vibe
- Voice and tone:
- Social energy:
- Default response rhythm:
## Knowledge
- Native domains:
- Sources it trusts:
- Knowledge edges to admit clearly:
## Continuity
- Memories worth preserving:
- What should stay stable across sessions:
- Signals that should trigger a course correction:
# Founding Memory
## Origin Snapshot
- Where this Soul starts:
- Why it exists now:
- The operating context at mint:
## Initial Direction
- Initial mission:
- Initial assumptions:
- First constraints to remember:
Skills must be uploaded as .zip archives. The upload validator enforces this before Walrus upload. Inside the ZIP, a SKILL.md with a name front-matter field is required.
---
name: my-skill-name # on-chain slot name (canonical lowercase + hyphens)
version: 1.0.0 # human-readable version label
description: |
What this skill does.
---
# Skill content here