Storage Layout
Every bin (your personal bin and each organization) is backed by a private GitHub directory repo. All writes go through the SkillsBin API as atomic Git commits, so the repo is a complete, human-readable, version-controlled mirror of your items.
Identity model
An item is identified by four coordinates:
(org, project, type, slug)- org — which directory repo the item lives in (personal bin or an organization).
- project — a grouping, usually named after a git repository. Items not assigned to a project live in the inbox (
_inbox). - type — one of the 13 item types (
skill,command,prompt,spec,plugin,agent,statusline,hook,mcp,rule,keybinding,script,secret). - slug — the item’s identifier, unique within its (org, project, type) folder.
This full identity is what sb put matches against when deciding between update and create — the same slug in a different project, or with a different type, is a different item. Uniqueness is enforced at create time: a taken slug gets a -2, -3, … suffix. Paths contain no random suffixes.
Path scheme
Each item owns one folder:
{project | _inbox}/{type-plural}/{slug}/The folder contains:
| File | Purpose |
|---|---|
| Main file | The item’s content, named by type (see below). |
sb.json | The manifest — identity, provenance, and timestamps. |
| Extra files | Any additional files, for multi-file types (skill, plugin). Statusline screenshots (screenshot.png/screenshot.jpg) also live here. |
The main file and sb.json are always written in the same commit.
Main filename by type
| Type | Folder | Main file |
|---|---|---|
skill | skills/ | SKILL.md |
command | commands/ | <slug>.md |
prompt | prompts/ | <slug>.md |
spec | specs/ | spec.md |
plugin | plugins/ | .claude-plugin/plugin.json |
agent | agents/ | <slug>.md |
statusline | statuslines/ | <slug>.sh |
hook | hooks/ | <slug>.sh |
mcp | mcps/ | <slug>.json |
rule | rules/ | CLAUDE.md |
keybinding | keybindings/ | <slug>.json |
script | scripts/ | <slug> (slug includes the extension) |
secret | secrets/ | secret.enc (encrypted envelope, see Secrets) |
Example tree
webapp/ ← project (from the "webapp" git repo)├── skills/│ └── deploy-helper/│ ├── SKILL.md│ ├── sb.json│ └── scripts/check.sh ← extra file uploaded with the skill├── specs/│ └── ci-plan/│ ├── spec.md│ └── sb.json└── secrets/ └── env/ ├── secret.enc ← ciphertext only; GitHub never sees plaintext └── sb.json_inbox/ ← items not assigned to any project└── commands/ └── my-command/ ├── my-command.md └── sb.jsonThe sb.json manifest
Every item folder carries an sb.json manifest, kept in sync with the item on each write:
{ "manifest_version": 2, "name": "Deploy Helper", "slug": "deploy-helper", "type": "skill", "project": "webapp", "description": "A skill that helps with deployments", "encrypted": false, "source_filename": "SKILL.md", "source": { "repo": "acme/webapp", "branch": "main", "path": ".claude/skills/deploy-helper/SKILL.md" }, "created_at": "2026-07-01T09:30:00+00:00", "updated_at": "2026-07-20T14:12:00+00:00"}| Field | Description |
|---|---|
manifest_version | Manifest schema version. Currently 2. |
name | Display name. |
slug | Item slug (matches the folder name). |
type | Item type. |
project | Project slug, or null for inbox items. |
description | Item description, or null. |
encrypted | true for secrets — the main file is a ciphertext envelope. |
source_filename | Original filename at upload time (used to restore secrets, for example). |
source | Provenance recorded by sb put from inside a git repo: repo (owner/name), branch, and path (repo-relative). null when uploaded outside a repo. |
created_at / updated_at | ISO-8601 timestamps. |
Revisions
Each sb put produces one Git commit, and SkillsBin records the commit SHA as a revision of the item. Because the path is stable, an item’s full history is the Git history of its folder.