How the Modly Artifact Registry Service Works: A Deep Dive into IPC-Driven Asset Management
The Modly artifact registry service is a secure, IPC-driven layer in electron/main/artifact-registry-service.ts that lists, reads, and opens workspace assets through strict path sandboxing, type classification, and metadata-driven linking.
The artifact registry is a core Electron main process service that bridges the renderer process with user workspace files. It exposes three IPC channels—workspace:library:list, workspace:library:read, and workspace:library:open—while enforcing that no file operations can escape the workspace sandbox. The implementation prioritizes security-by-default through path normalization, traversal prevention, and capability-based asset classification.
Path Safety and Normalization
Before any file operation occurs, the registry validates and normalizes all paths to prevent directory traversal attacks.
Strict Path Validation
The assertSafeWorkspaceRelativePath function (lines 84-95) enforces four rules:
- The path must be relative (no leading slash or drive letter)
- No URL-encoded escapes (e.g.,
%2e%2efor..) - No traversal segments (
..anywhere in the path) - No disallowed root patterns (hidden internals)
// This would throw an error
assertSafeWorkspaceRelativePath('../../../etc/passwd');
assertSafeWorkspaceRelativePath('Exports/../../secret.txt');
Workspace-Root Resolution
The normalizeWorkspaceAssetPath function (lines 97-104) resolves the validated relative path against the workspace root, guaranteeing the final absolute path remains inside the sandbox. Even if the validation logic had subtle bugs, the resolution step provides a defense-in-depth boundary.
Asset Classification System
The registry determines what each file is and what it can do through classifyAssetLibraryCandidate (lines 118-143).
Capability Detection
Classification inspects both file extensions and accompanying metadata files (.rig.json sidecars):
| Pattern | Capability | Openable? |
|---|---|---|
.glb with no rig |
mesh |
Yes |
.glb with .rig.json |
rigged-mesh |
Yes |
.fbx animation clip |
animation-motion |
Yes |
_landmarks.json sidecar |
landmark-data |
No |
world.json manifest |
generated-world |
Yes |
Special cases—landmark sidecars, generated worlds, and scene manifests—have explicit handling rather than falling through generic logic.
Metadata Extraction and Link Safety
Registry entries can carry provenance metadata that links back to source files or upstream workspaces.
Sidecar Parsing
The readMetadata function (lines 179-204) parses .json sidecar files and extracts:
sourceWorkspacePath: Origin file in another workspacemanifestWorkspacePath: Containing scene/generation contextartifactIdandversionId: Registry identifiersprovenance: Audit trail data
Safe Link Validation
Each linked path undergoes validation through safeLinkedWorkspacePath (lines 59-77), which applies the same traversal protections to external references. Warnings accumulate for:
- Missing sidecar files
- Unsafe linked paths that fail validation
- Version mismatches between sidecar and actual file
Entry Construction and Traversal
Building the Asset Entry
The buildEntry function (lines 225-250) assembles the final AssetLibraryEntry object:
interface AssetLibraryEntry {
workspacePath: string; // Normalized relative path
absolutePath: string; // Resolved sandboxed path
name: string;
extension: string;
sizeBytes: number;
modifiedAt: number;
capability: AssetCapability;
state: AssetState;
openable: boolean;
metadata?: AssetMetadata;
}
Filesystem Walking
collectFiles (lines 252-275) performs a constrained directory traversal of two allowed roots:
Workflows/: Source assets and work-in-progress filesExports/: Generated outputs and final artifacts
It explicitly skips:
- Hidden directories (
.git,.modly) - Temporary folders (
__temp__,.tmp) - Internal sidecar files (handled as metadata attachments, not standalone entries)
Public API Methods
Listing Assets
listWorkspaceAssetLibrary (lines 777-785) returns an AssetLibraryListResult containing all valid entries, pre-filtered to exclude unsupported or corrupted assets.
const result = await ipcRenderer.invoke('workspace:library:list');
// result.entries: AssetLibraryEntry[]
// result.warnings: ValidationWarning[]
Reading with Preview Generation
readWorkspaceAssetLibraryEntry (lines 801-808) builds a complete entry and delegates to previewEntry (lines 887-998) to generate renderer-ready payloads:
| Preview Type | Use Case |
|---|---|
| Text | Shaders, JSON manifests, code |
| Binary | Raw buffer for custom parsers |
| 3D Model | Three.js-compatible GLB/GLTF data |
Opening Assets
openWorkspaceAssetLibraryEntry (lines 835-843) confirms the asset is openable (or that a valid sourceWorkspacePath override was provided) before returning the entry. This prevents UI states where non-interactive assets would attempt to load into editors.
IPC Registration and Channel Security
The registerWorkspaceAssetLibraryIpcHandlers function (lines 554-566) wires the service into ipcMain:
ipcMain.handle('workspace:library:list', listWorkspaceAssetLibrary);
ipcMain.handle('workspace:library:read', readWorkspaceAssetLibraryEntry);
ipcMain.handle('workspace:library:open', openWorkspaceAssetLibraryEntry);
All three handlers accept only the pre-defined payload shapes from src/shared/types/assetLibrary.ts, rejecting malformed messages at the serialization boundary.
Renderer-Side Usage
The frontend service at src/areas/generate/assetLibraryService.ts forwards calls through these IPC channels. UI components in src/areas/generate/assetLibraryUi.ts consume the resulting data for asset browsing and 3D preview panels.
// Fetch workspace assets
const assets = await ipcRenderer.invoke('workspace:library:list');
// Read specific asset with preview
const { entry, preview } = await ipcRenderer.invoke(
'workspace:library:read',
{ workspacePath: 'Exports/character.glb' }
);
// Open for editing
const openResult = await ipcRenderer.invoke(
'workspace:library:open',
{ workspacePath: 'Exports/character.glb' }
);
Summary
- Strict sandboxing via
assertSafeWorkspaceRelativePathandnormalizeWorkspaceAssetPathprevents filesystem escape - Capability classification through
classifyAssetLibraryCandidateenables type-aware UI rendering - Metadata-driven linking with
safeLinkedWorkspacePathvalidates cross-workspace references - Three IPC channels—
list,read,open—expose all functionality to the renderer - Preview generation in
previewEntrybridges raw files to renderable formats
Frequently Asked Questions
How does Modly prevent directory traversal attacks in the artifact registry?
The service implements double validation: assertSafeWorkspaceRelativePath (lines 84-95) rejects traversal segments, encoded escapes, and absolute paths before normalizeWorkspaceAssetPath (lines 97-104) resolves against the workspace root. Even if validation were bypassed, the resolution step guarantees the final path stays within the sandbox.
What file types can the Modly artifact registry open directly?
Openability depends on capability classification in classifyAssetLibraryCandidate (lines 118-143). Mesh files (.glb, .gltf), rigged meshes with .rig.json sidecars, animation motions, and generated world manifests are openable. Landmark sidecars and internal metadata files return openable: false and display as read-only reference data.
How does the registry handle assets that originated in other workspaces?
The readMetadata function (lines 179-204) extracts sourceWorkspacePath from sidecar files, then safeLinkedWorkspacePath (lines 59-77) validates this external reference against the same traversal rules. The read and open handlers accept an optional sourceWorkspacePath override to resolve the canonical asset when a local copy is a derivative export.
Where are the core types for the artifact registry defined?
Shared type definitions—including AssetLibraryEntry, AssetCapability, AssetState, and IPC payload shapes—reside in src/shared/types/assetLibrary.ts. The main process implementation is in electron/main/artifact-registry-service.ts, with frontend service wrappers in src/areas/generate/assetLibraryService.ts.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →