⚠️ mlld is pre-release
Join the discord if you have questions. Report bugs on GitHub.
mlld Resolvers
tldr
Resolvers control how mlld imports find content. Use custom resolvers to create @ -prefixed aliases for local paths, private repos, or any content source. Configure with mlld setup or mlld alias.
Built-in Resolvers
mlld includes resolvers for common sources:
Registry Resolver
Registry modules from mlld-lang/registry:
/import { @helper } from @alice/utils
/import { @helper } from @alice/utils@1.0.0
/import { @helper } from @alice/utils@beta
/import { @helper } from @alice/utils@^1.0.0
- Requires:
mlld install @alice/utils - Offline after install
- Version-locked via mlld-lock.json
- Content-addressed caching
- Supports version specifiers (@module@1.0.0)
- Supports tags (@module@beta, @module@latest)
- Supports semver ranges (@module@^1.0.0, @module@~1.2.0)
Local Resolver
Project-relative file paths:
/import { @config } from <./config.mld>
/import { @helpers } from <../shared/utils.mld>
- Reads from filesystem
- No caching (always fresh)
- Relative to current file
- Fuzzy file extension matching (tries
.mld,.mld.md,.md) - Automatic extension resolution (you can omit the extension)
HTTP Resolver
Web resources via HTTPS/HTTP:
/import cached(1h) <https://example.com/utils.mld> as @remote
- Caches with TTL (time-to-live)
- Validates via ETag/Last-Modified
- Default TTL: 5 minutes
GitHub Resolver
GitHub repositories and raw URLs:
/import <https://raw.githubusercontent.com/alice/repo/main/module.mld> as @mod
- Works with public repos
- Supports branch/tag/commit references
- Caches by commit SHA
Static Import Type
Not a separate resolver - an import type that uses existing resolvers but embeds content at parse time:
/import static <./prompt.md> as @systemPrompt
- Content embedded in AST during evaluation
- Zero runtime fetch cost after initial load
- Good for templates/prompts
- Works with any resolver (Local, HTTP, GitHub, etc.)
Local Development Mode
Not a separate resolver - configuration of LocalResolver for development:
/import local { @helper } from @alice/dev-module
- Uses LocalResolver configured to read from
llm/modules/ - Scans flat directory structure (all
.mldfiles at the top level) - Matches module name from frontmatter metadata (
author+name) - Module files should be named descriptively but matching happens via frontmatter
- No caching (always fresh)
- Bypasses registry entirely
Directory structure:
llm/modules/
├── helper-utils.mld # Has: author: alice, name: dev-module
├── auth-tools.mld # Has: author: bob, name: auth
└── data-parser.mld # Has: author: alice, name: parser
Not this:
llm/modules/
└── @alice/ # ❌ Nested paths won't be discovered
└── dev-module.mld
Custom Resolvers
Create @ -prefixed aliases for any content source.
Quick Setup
Interactive wizard:
mlld setup
Prompts for:
- Alias name (e.g.,
@notes/) - Path or repo URL
- Access type (input/output/both)
Local Path Alias
Map @ prefix to local directory:
mlld alias --name notes --path ~/Documents/notes
Creates resolver in mlld-config.json:
{
"resolvers": {
"prefixes": [
{
"prefix": "@notes/",
"resolver": "LOCAL",
"type": "input",
"config": {
"basePath": "/Users/you/Documents/notes"
}
}
]
}
}
Use it:
/import <@notes/ideas.md> as @ideas
/show @ideas
Private GitHub Repo
Connect private repo:
mlld setup --github
Prompts for:
- Organization/username
- Repository name
- Branch (default: main)
- Base path (default: /)
Creates resolver:
{
"resolvers": {
"prefixes": [
{
"prefix": "@company/",
"resolver": "GITHUB",
"type": "input",
"config": {
"repository": "company/private-modules",
"branch": "main",
"basePath": "llm/modules"
}
}
]
}
}
Use it:
/import { @auth } from @company/auth-utils
Requires GitHub auth:
mlld auth login
Global Aliases
Make alias available everywhere:
mlld alias --name desktop --path ~/Desktop --global
Saves to ~/.config/mlld/mlld-config.json.
Resolver Configuration
Manual Configuration
Edit mlld-config.json:
{
"resolvers": {
"prefixes": [
{
"prefix": "@lib/",
"resolver": "LOCAL",
"type": "input",
"config": {
"basePath": "./src/lib"
}
},
{
"prefix": "@shared/",
"resolver": "LOCAL",
"type": "input",
"config": {
"basePath": "../shared-modules"
}
},
{
"prefix": "@private/",
"resolver": "GITHUB",
"type": "input",
"config": {
"repository": "user/private-mlld",
"branch": "main",
"basePath": "modules"
}
}
]
}
}
Resolver Types
LOCAL - Filesystem paths
{
"prefix": "@notes/",
"resolver": "LOCAL",
"config": {
"basePath": "/path/to/notes"
}
}
GITHUB - GitHub repositories
{
"prefix": "@org/",
"resolver": "GITHUB",
"config": {
"repository": "org/repo",
"branch": "main",
"basePath": "llm/modules"
}
}
HTTP - Web resources
{
"prefix": "@cdn/",
"resolver": "HTTP",
"config": {
"baseUrl": "https://cdn.example.com/modules",
"cacheTTL": "1h"
}
}
Access Types
Control import/output permissions:
input - Import only (read)
{
"type": "input"
}
output - Output only (write)
{
"type": "output"
}
io - Both import and output
{
"type": "io"
}
Resolution Priority
When multiple resolvers could handle an import, priority determines which wins:
- Exact prefix match -
@notes/matches@notes/ideas.md - Longest prefix -
@company/auth/beats@company/ - Import type - Explicit type overrides prefix matching
- Built-in priority - Registry > Local > HTTP
Example:
# These all resolve differently
/import { @x } from @alice/utils # Registry resolver
/import local { @x } from @alice/utils # Local dev resolver
/import <@notes/utils.mld> as @x # Custom @notes/ resolver
Resolver Patterns
Project Organization
mlld alias --name lib --path ./src/lib
mlld alias --name shared --path ../shared
mlld alias --name tests --path ./tests
Import cleanly:
/import { @api } from @lib/api
/import { @common } from @shared/utils
/import { @fixtures } from @tests/fixtures
Team Modules
{
"resolvers": {
"prefixes": [
{
"prefix": "@team/",
"resolver": "GITHUB",
"type": "input",
"config": {
"repository": "company/team-modules",
"branch": "main"
}
}
]
}
}
Team members import:
/import { @logger } from @team/logging
/import { @db } from @team/database
Multi-Environment
{
"resolvers": {
"prefixes": [
{
"prefix": "@prod/",
"resolver": "GITHUB",
"config": {
"repository": "company/configs",
"branch": "production"
}
},
{
"prefix": "@staging/",
"resolver": "GITHUB",
"config": {
"repository": "company/configs",
"branch": "staging"
}
}
]
}
}
Use appropriate alias:
/import <@prod/config.mld> as @config
# or
/import <@staging/config.mld> as @config
Personal Library
Global alias for personal modules:
mlld alias --name me --path ~/mlld-modules --global
Available in any project:
/import { @snippet } from @me/snippets
/import <@me/prompts/code-review.md> as @prompt
Security Configuration
Control what resolvers can access:
Allowed Domains
{
"security": {
"allowedDomains": [
"raw.githubusercontent.com",
"gist.githubusercontent.com",
"cdn.example.com"
]
}
}
Trusted Domains
Skip approval prompts:
{
"security": {
"trustedDomains": [
"raw.githubusercontent.com"
]
}
}
Blocked Patterns
{
"security": {
"blockedPatterns": [
"*.evil.com",
"http://*"
]
}
}
Absolute Paths
Control absolute filesystem access:
{
"security": {
"allowAbsolutePaths": false
}
}
Requires flag when enabled:
mlld --allow-absolute script.mld
Caching Behavior
Different resolvers cache differently:
Registry Modules
- Content-addressed cache in
.mlld/cache/ - Keyed by SHA256 hash
- Never expires (immutable)
- Offline-capable after install
Local Files
- No caching
- Read fresh every time
- Detects changes immediately
HTTP Resources
- Cached with TTL
- Validates with ETag/Last-Modified
- Default TTL: 5 minutes
- Override with
cached(TTL)
GitHub Resources
- Cached by commit SHA
- Permanent for commit references
- Revalidated for branch references
Import Type Override
Force specific resolver:
# Force static (embed)
/import static <https://example.com/data.json> as @data
# Force live (always fresh)
/import live <./config.mld> as @config
# Force cached with TTL
/import cached(30m) <@company/utils.mld> as @utils
# Force local dev
/import local { @helper } from @alice/utils
Import type takes precedence over resolver configuration.
Commands
Setup Resolvers
mlld setup # Interactive wizard
mlld setup --github # GitHub only
mlld setup --local # Local paths only
mlld setup --check # Verify config
mlld setup --add-resolver # Add new resolver
Create Alias
mlld alias --name <alias> --path <path>
mlld alias --name <alias> --path <path> --global
Check Configuration
mlld setup --check
Shows:
- Configured resolvers
- Prefix mappings
- Access types
- Validity status
Troubleshooting
Resolver Not Found
Symptom: Unknown resolver prefix: @notes/
Fix: Create resolver:
mlld alias --name notes --path /path/to/notes
Permission Denied
Symptom: Access denied for resolver @company/
Fix: Check access type in config. Should be input or io for imports.
GitHub Auth Failed
Symptom: GitHub authentication required
Fix:
mlld auth login
Cache Issues
Symptom: Getting stale content
Fix: Adjust caching:
# Force fresh
/import live <@resolver/module.mld> as @mod
# Shorter TTL
/import cached(1m) <@resolver/module.mld> as @mod
Path Not Found
Symptom: Module not found: @lib/utils
Fix: Verify basePath in config:
mlld setup --check
Ensure files exist at configured path.
Best Practices
Use prefixes consistently:
@lib/for library code@shared/for shared modules@company/for org modules
Document team aliases:
Include resolver config in README for team projects.
Separate dev and prod:
/import local { @db } from @team/database # Dev
# vs
/import { @db } from @team/database # Prod (registry)
Version control config:
Commit mlld-config.json for reproducible imports.
Use global sparingly:
Reserve global aliases for truly personal modules.
Test resolver changes:
mlld setup --check # Before committing
Examples
Company Setup
{
"resolvers": {
"prefixes": [
{
"prefix": "@company/",
"resolver": "GITHUB",
"type": "input",
"config": {
"repository": "company/mlld-modules",
"branch": "main",
"basePath": "modules"
}
},
{
"prefix": "@internal/",
"resolver": "HTTP",
"type": "input",
"config": {
"baseUrl": "https://internal.company.com/modules",
"cacheTTL": "1h"
}
}
]
}
}
Multi-Project Setup
{
"resolvers": {
"prefixes": [
{
"prefix": "@project-a/",
"resolver": "LOCAL",
"config": { "basePath": "../project-a/modules" }
},
{
"prefix": "@project-b/",
"resolver": "LOCAL",
"config": { "basePath": "../project-b/modules" }
},
{
"prefix": "@shared/",
"resolver": "LOCAL",
"config": { "basePath": "../shared-modules" }
}
]
}
}
Use across projects:
/import { @helpers } from @shared/utils
/import { @api } from @project-a/client
/import { @types } from @project-b/schema