Folder layout
harbor/ satchel.json # manifest (required) identity/persona.md instructions/house-rules.md memory/stack.md skills/changelog-writer/SKILL.md skills/changelog-writer/scripts/collect_prs.sh checksums # "sha256 path" per entry
Tools, routines, permissions and model settings are small structured records, so they live in the manifest. Everything a human would read lives in its own Markdown file.
Manifest
{
"$schema": "https://satchery.pro/schema/satchel-1.json",
"format": "satchel",
"formatVersion": 1,
"agent": { "id": "<uuid>", "name": "Harbor", "slug": "harbor", "description": "…" },
"origin": { "platform": "claude-code", "packedAt": "2026-11-15T00:00:00.000Z", "packedBy": "satchery 0.1.0" },
"secrets": [ { "name": "GITHUB_TOKEN", "item": "tools/github", "where": "env.GITHUB_TOKEN" } ],
"items": [ … ]
}
agent.idis a UUID that stays the same across moves, so the next platform can tell it is the same agent.agent.slug(optional) uses lowercase letters, digits, dot, dash or underscore.origin.platformnames the platform the satchel was packed from.
Items
Every item has a category, an id (unique within its category), a name, and where it applies a file (a safe relative path) and a data object. Items can carry a source with the platform and path they were read from.
{ "id": "github", "category": "tools", "name": "github",
"data": { "transport": "stdio", "command": "npx", "args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_TOKEN": "{{secret:GITHUB_TOKEN}}" } },
"source": { "platform": "claude-code", "path": ".mcp.json" } }
Category rules
- identity, instructions, memory, skills need a
file. Skills may list extra files (scripts, references) indata.files. - tools:
data.transportisstdio(needscommand),httporsse(needurl). - routines: need
data.prompt;data.scheduleis a cron string. A routine that is not paused is paused on import. - permissions:
data.modeis one ofreadonly,ask,auto,full;allow,askanddenyare lists of rule strings. - models: need
data.model;data.provideris optional.
Secret references
Secret values are taken out before anything is packed. API keys, tokens, bearer headers, private keys, passwords in URLs, .env-style values and MCP env values are replaced by {{secret:NAME}}. The manifest lists the names and where each one was used, so you know what to reconnect. Names use capital letters, digits and underscores. Detection is pattern-based: it covers known key and token formats, secret-looking NAME=value lines, bearer headers, URL passwords and every MCP env value, so read the plan before you share a satchel.
The .satchel file
A .satchel is a gzip-compressed tar of the folder, including checksums: one line per entry with its sha256 and path, sorted by path. Packing the same satchel twice gives the same bytes.
Checksums make changes visible; they are not a signature. A .satchel is not encrypted and not signed, so only open satchels from people you trust.
Limits a reader enforces
- Only regular files and folders. Symbolic and hard links are refused.
- No absolute paths, no
.., no backslashes, no duplicate entries. - At most 2,000 entries, 10 MB per file, 64 MB unpacked, 32 MB compressed.
- Every entry must match its checksum, and every checksum must have its entry.
Validation
The inspector runs the same reader and validator as the CLI, in your browser. Errors stop a move; warnings (for example a routine that is not paused) are shown and handled.