Mist Domain
A Mist is a content-addressed, cryptographically signable, forkable,
embeddable artifact share — what a gist becomes when you reimagine it through the full
Muse philosophy. Every Mist is a Muse repo with domain="mist", giving it
full branching, time-travel, signed commits, and MCP tooling for free.
Concepts
| Property | Value |
|---|---|
| Identity | Content-addressed — SHA-256 over content bytes, base-58 encoded, truncated to 12 chars |
| Storage | Every Mist is a Muse repo with domain="mist" |
| Versioning | Full muse log, muse diff, muse checkout on the backing repo |
| Authorship | Optional Ed25519 (--sign) or GPG signature proving human/agent identity |
| Visibility | public (default) or secret |
| Forkability | Any public Mist is forkable; fork depth capped at 5 |
| Embeddability | Standalone iframe card served at /{owner}/mists/{id}/embed |
URL schema
# Web UI
/{owner}/mists/{mist_id} # detail page
/{owner}/mists/{mist_id}/embed # iframe-safe embed card
/{owner}/mists/{mist_id}/raw # raw artifact download
/{owner}/mists # owner's public mist list
/mists/explore # global discovery feed
# REST API
POST /api/mists # create
GET /api/mists/{mist_id} # read
PATCH /api/mists/{mist_id} # update (owner only)
DELETE /api/mists/{mist_id} # delete (owner only)
POST /api/mists/{mist_id}/fork # fork
GET /api/mists/{mist_id}/forks # list direct forks
GET /api/mists/explore # global public feed
GET /api/{owner}/mists # owner's public list
# MCP Resource
musehub://mists/{owner}/{mist_id} # single mist resource
musehub://mists/{owner} # owner's mist list resource
Artifact types
The server auto-detects the artifact type from the filename and content bytes.
Callers may omit artifact_type in POST /api/mists — the
server fills it in. Symbol anchors are extracted automatically for Python, JavaScript,
and TypeScript code artifacts.
| Type | Detection heuristic | Language detection |
|---|---|---|
code | Common code extensions (.py, .js, .ts, .rs, .go, …) | Yes — from extension |
midi | .mid / .midi extension or MIDI magic bytes (4D 54 68 64) | No |
schema | .json + JSON content with $schema or type/properties keys | No |
abi | .abi, .abi.json, or JSON array of ABI objects | No |
dataset | .csv, .tsv, .ndjson, .jsonl | No |
config | .yaml, .yml, .toml, .env, .ini, .conf | No |
text | .md, .txt, .rst, .adoc or unrecognised text | No |
unknown | Binary content with no recognised signature | No |
CLI reference
The muse mist subcommand is the primary interface for humans and agents.
Create
muse mist create <file> [options]
--title TEXT Human-readable title
--description TEXT Longer description (shown on the detail page)
--visibility public (default) | secret
--tags TAG,... Comma-separated tags (max 10, 64 chars each)
--agent-id TEXT Agent identifier for provenance
--model-id TEXT Model ID for agent provenance
--sign Sign with the local Ed25519 identity key
--push Push to the configured hub after creation
--json Machine-readable output
muse mist create validate_handle.py \
--title "Handle validation primitive" \
--tags "security,auth" \
--sign --push --json
# → {"mist_id": "aB3xKq9dPwNm", "url": "http://staging.musehub.ai/gabriel/mists/aB3xKq9dPwNm", ...}
Other commands
| Command | Description |
|---|---|
muse mist list [--owner HANDLE] [--artifact-type TYPE] [--json] | List mists |
muse mist read <mist_id> [--json] | Fetch a single mist |
muse mist fork <mist_id> [--push] [--json] | Fork a public mist |
muse mist update <mist_id> [--title ...] [--content FILE] [--json] | Partial update (owner only) |
muse mist delete <mist_id> [--json] | Hard delete (owner only) |
REST API
All write endpoints require Authorization: MSign ... (see Cryptographic Identity).
POST /api/mists
Create a new mist. The mist_id is computed by the server.
{
"filename": "validate_handle.py",
"content": "def _validate_handle(h): ...",
"visibility": "public",
"title": "Handle validation primitive",
"description": "Security gate used by auth middleware.",
"tags": ["security", "auth"],
"agentId": "cccode-v3",
"modelId": "claude-sonnet-4-6"
}
Returns 201 with the full mist object. Returns 409 if the same content already exists under your handle (idempotent — the existing mist_id is stable).
GET /api/mists/explore
Global public discovery feed. Supports artifact_type and cursor pagination.
GET /api/mists/explore?artifact_type=code&limit=20&cursor=<ISO-8601>
{
"mists": [...],
"total": 1234,
"nextCursor": "2026-04-14T09:30:00+00:00"
}
PATCH /api/mists/{mist_id}
Partial update. Only provided fields change. Updating content increments version and records a new commit on the backing repo. Returns 404 if not found or caller is not the owner.
DELETE /api/mists/{mist_id}
Hard delete. Returns 204 on success, 404 if not found or not the owner.
POST /api/mists/{mist_id}/fork
Create a fork. Returns 422 if the parent is already at fork depth 5.
MCP tools & resources
| Tool | Auth | Description |
|---|---|---|
muse_mist_create | write | Create a new Mist |
muse_mist_update | write | Patch title/description/visibility/tags/content |
muse_mist_fork | write | Fork a public Mist |
muse_mist_delete | write | Hard-delete a Mist (owner only) |
muse_mist_read | read | Fetch full Mist including content |
muse_mist_raw | read | Fetch raw artifact content as a plain string |
muse_mist_list | read | List mists (owner or global explore) |
muse_mist_list_forks | read | List direct forks of a Mist |
muse_mist_embed | read | Get iframe, script, and badge embed codes |
Resources:
musehub://mists/{owner}/{mist_id} — full mist response (content included)
musehub://mists/{owner} — owner's public mist list (no content)
Secret mists are returned for the authenticated owner; unauthenticated or non-owner reads return a forbidden error.
Agent publishing workflow
An agent session produces an artifact it wants to share permanently:
# Via MCP tool (no shell required):
result = muse_mist_create(
filename="validate_handle.py",
content=content,
title="Handle validation security primitive",
agent_id="cccode-v3",
model_id="claude-sonnet-4-6",
visibility="public",
tags=["security", "auth"],
)
# → {"mistId": "aB3xKq9dPwNm", "url": "http://staging.musehub.ai/gabriel/mists/aB3xKq9dPwNm", ...}
# Or via CLI (signed with MUSE_AGENT_KEY env var injected by Agentception):
muse mist create /tmp/validate_handle.py \
--title "Handle validation security primitive" \
--agent-id cccode-v3 \
--model-id claude-sonnet-4-6 \
--sign --push --json
The resulting URL is a permanent, verifiable artifact. The agent_id and
model_id fields prove provenance. In the ERC-8004 on-chain identity world:
agent contract address → MSign key → Mist signature → content hash.
Forking & sub-domain delegation
Every Mist is a Muse repo (domain="mist"). Forking creates a new repo whose
first commit copies the parent's content. The fork graph is visible on the detail page
sidebar (Forked From + Forks panels).
Sub-domain delegation (future): Because each Mist backs a full Muse repo, any future domain plugin (genomics, spatial, MIDI v2) can be applied to the backing repo, gaining symbol-level diffs, blast radius, and AST versioning for free.
Embedding
iframe
<iframe
src="http://staging.musehub.ai/{owner}/mists/{mist_id}/embed"
width="600"
height="400"
frameborder="0"
title="my_file.py">
</iframe>
Script tag
<script
src="http://staging.musehub.ai/embed.js"
data-mist="{owner}/{mist_id}">
</script>
The embed card shows the artifact type chip, filename, syntax-highlighted content,
size/version metadata, and a "View on MuseHub" link. The embed endpoint increments
embed_count on each render. Cross-origin framing is allowed
(frame-ancestors *).
Content addressing
The mist_id is computed deterministically from the artifact bytes:
import hashlib, base58
def compute_mist_id(content: bytes) -> str:
digest = hashlib.sha256(content).digest()
return base58.b58encode(digest).decode()[:12]
| Property | Detail |
|---|---|
| Deterministic | The same file always produces the same mist_id |
| Collision-resistant | SHA-256 with 12-char base-58 → ~7×10¹⁶ distinct IDs |
| Offline verifiable | Any caller can recompute the ID and confirm integrity without contacting the server |
| Idempotent creates | POST /api/mists with the same content returns 409 — the existing Mist is not overwritten |
Security model
| Threat | Mitigation |
|---|---|
| Path traversal via filename | _validate_mist_filename() rejects .., /, \, null bytes, control chars, ANSI escapes |
| Content injection (XSS) | Content stored verbatim; Jinja2 auto-escapes at render time |
| Oversized content | ContentSizeLimitMiddleware returns 413 for bodies > 10 MiB |
| Unauthorised mutation | PATCH/DELETE check mist.owner == caller.handle; return 404 on mismatch |
| Secret mist leakage | Secret mists excluded from /explore and owner list; direct GET returns 403 |
| Fork bomb | Depth cap enforced at service layer (_FORK_DEPTH_LIMIT = 5) and REST route (422) |
| Rate limiting | MIST_CREATE_LIMIT = 20/min, MIST_FORK_LIMIT = 30/min per MSign handle |
| Tag injection | validate_tags() enforces count ≤ 10, length ≤ 64, no null bytes |
Limits
| Parameter | Limit |
|---|---|
| Content size | 10 MiB (enforced by middleware) |
| Filename length | 255 characters |
| Title length | 500 characters |
| Description length | 10,000 characters |
| Tag count | 10 |
| Tag length | 64 characters |
| Fork depth | 5 |
| Create rate | 20 / minute per handle |
| Fork rate | 30 / minute per handle |
| Explore page size | 1–100 (default 20) |