Skip to main content

Configuration API

datamitsu uses JavaScript configuration files powered by the goja JavaScript runtime. Configuration is defined in datamitsu.config.js, datamitsu.config.mjs, or datamitsu.config.ts at your git repository root.

Required Exports

Every config file must export:

  • getMinVersion() — Returns a semver string specifying the minimum datamitsu version required. Checked before getConfig() is called. Configs without this function fail to load.
  • getConfig(config) — Receives the previous layer's config and returns a new Config object.
  • getRemoteConfigs() (optional) — Returns remote parent configs to load before this config.
function getMinVersion(): string;
function getConfig(config: Config): Config;
function getRemoteConfigs(): Array<{ url: string; hash: string }>;

The special version "dev" (used when running from source) is treated as v0.0.0.

Config Structure

The getConfig() function returns a Config object:

interface Config {
apps?: BinManager.MapOfApps;
runtimes?: BinManager.MapOfRuntimes;
bundles?: Record<string, Bundle>;
tools?: MapOfTools;
projectTypes?: MapOfProjectTypes;
init?: MapOfConfigInit;
initCommands?: MapOfInitCommands;
ignoreRules?: string[];
sharedStorage?: Record<string, string>;
}

Config Loading Order

Configuration is loaded in layers, each receiving the previous result as input:

default (embedded config.js)
↓ [getRemoteConfigs() resolved depth-first, if exported]
--before-config flags (for wrappers/libraries)
↓ [getRemoteConfigs() resolved depth-first]
auto (datamitsu.config.{js,mjs,ts} at git root)
↓ [getRemoteConfigs() resolved depth-first]
--config flags (for CI/testing overrides)

final Config
  • Each source must export getMinVersion() — version is checked before getConfig() runs (fail-fast)
  • Each source can export getRemoteConfigs() returning Array<{url: string, hash: string}> for recursive parent resolution
  • ignoreRules use append semantics across config layers
  • Circular remote config dependencies are detected and produce an error

Apps (apps)

Apps define the tools datamitsu manages. The app kind is determined by which sub-object is present (binary, uv, node, jvm, go, or shell).

App Kinds

KindSub-objectDescription
binarybinarySelf-managed binaries downloaded from URLs
uvuvPython packages installed via managed UV runtime
nodenodenpm packages installed via managed Node.js + pnpm
jvmjvmJava applications executed via managed JDK
gogoGo tools built from source via managed Go SDK
shellshellShell commands with custom environment

Common App Fields

All app kinds share these optional fields:

interface AppCommon {
required?: boolean; // Whether the app is required for init
files?: Record<string, string>; // filename → static content
links?: Record<string, string>; // linkName → relativePath in install dir
archives?: Record<string, ArchiveSpec>; // name → archive specification
env?: Record<string, string>; // Custom environment variables (all app kinds)
versionCheck?: {
disabled?: boolean; // Skip version check in verify-all
args?: string[]; // Override default ["--version"] args
};
}

Custom environment variables (env)

The optional env field applies to every app kind (binary, uv, node, jvm, go, shell). It is injected both at install time (for the uv/node/go dependency-install phase) and at run time (every app type).

Values support placeholder expansion, performed in Go and never written into the committed config:

  • ${STORE} → the shared datamitsu store path (cleaned by datamitsu store clear).
  • ${APP_DIR} → this app's install directory (per-app, config-hashed).

Precedence: any key already set by datamitsu or the runtime wins. A user config can never relocate the pnpm store, uv cache, GOPATH, etc.

const apps = {
slidev: {
node: {
packageName: "@slidev/cli",
// ...
},
// Redirect playwright to download browsers into the datamitsu store
env: { PLAYWRIGHT_BROWSERS_PATH: "${STORE}/.playwright/browsers" },
},
};

Migration (alpha breaking change): env was previously a field on AppConfigShell (shell.env). It has moved to the top-level env field shared by all app kinds. Move any shell: { env: {...} } up one level to env: {...} on the app.

Binary Apps

Binary apps download platform-specific executables with hash verification.

const apps = {
"golangci-lint": {
binary: {
version: "2.1.0",
binaries: {
linux: {
amd64: {
glibc: {
url: "https://github.com/golangci/golangci-lint/releases/download/v2.1.0/golangci-lint-2.1.0-linux-amd64.tar.gz",
hash: "abc123...", // SHA-256 (mandatory)
contentType: "tar.gz",
binaryPath: "golangci-lint-2.1.0-linux-amd64/golangci-lint",
},
},
},
darwin: {
arm64: {
unknown: {
url: "https://github.com/golangci/golangci-lint/releases/download/v2.1.0/golangci-lint-2.1.0-darwin-arm64.tar.gz",
hash: "def456...",
contentType: "tar.gz",
binaryPath: "golangci-lint-2.1.0-darwin-arm64/golangci-lint",
},
},
},
},
},
},
};

Binary-specific fields:

interface AppConfigBinary {
version?: string;
binaries: Partial<
Record<OsType, Partial<Record<ArchType, Partial<Record<LibcType, BinaryOsArchInfo>>>>>
>;
}

interface BinaryOsArchInfo {
url: string;
hash: string; // SHA-256 hash (mandatory)
contentType: BinContentType;
binaryPath?: string; // Path to binary within archive
extractDir?: boolean; // Extract entire archive to directory
}

The binaries map uses a three-level nested structure: os → arch → libc → BinaryOsArchInfo. Linux platforms use "glibc" or "musl" as the libc key; non-Linux platforms use "unknown".

Supported platforms: darwin/amd64/unknown, darwin/arm64/unknown, linux/amd64/glibc, linux/amd64/musl, linux/arm64/glibc, linux/arm64/musl, freebsd/amd64/unknown, openbsd/amd64/unknown, windows/amd64/unknown, windows/arm64/unknown

Supported archive types: tar.gz, tar.xz, tar.bz2, tar.zst, tar, zip, gz, bz2, xz, zst, binary

UV Apps (Python)

UV apps install Python packages in isolated environments using the managed UV runtime.

const apps = {
yamllint: {
uv: {
packageName: "yamllint",
version: "1.35.1",
requiresPython: ">=3.12", // optional, defaults to ">=3.12"
lockFile: "br:...", // brotli-compressed lock file (required)
runtime: "uv-default", // optional runtime override
},
},
};

UV-specific fields:

interface AppConfigUV {
packageName: string;
version: string;
requiresPython?: string; // Defaults to ">=3.12"
lockFile: string; // Brotli-compressed with "br:" prefix (required)
runtime?: string; // Runtime name override
}

Node Apps (Node.js/npm)

Node apps install npm packages using the managed Node.js runtime and pnpm.

const apps = {
eslint: {
node: {
packageName: "eslint",
version: "9.27.0",
binPath: "node_modules/.bin/eslint",
dependencies: {
"typescript-eslint": "^8.32.0",
"@eslint/js": "^9.27.0",
},
lockFile: "br:...", // brotli-compressed lock file (required)
runtime: "node-default", // optional runtime override
},
links: {
"eslint-config": "dist/eslint.config.js",
},
},
};

Node-specific fields:

interface AppConfigNode {
binPath: string; // Path to binary (e.g., "node_modules/.bin/eslint")
packageName: string;
version: string;
lockFile: string; // Brotli-compressed with "br:" prefix (required)
dependencies?: Record<string, string>;
runtime?: string; // Runtime name override
}

JVM Apps (Java)

JVM apps download JAR files and execute them via a managed JDK.

const apps = {
"openapi-generator-cli": {
jvm: {
version: "7.12.0",
jarUrl:
"https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.12.0/openapi-generator-cli-7.12.0.jar",
jarHash: "abc123...", // SHA-256 (mandatory)
runtime: "jvm-default",
},
},
};

JVM-specific fields:

interface AppConfigJVM {
version: string;
jarUrl: string;
jarHash: string; // SHA-256 hash (mandatory)
mainClass?: string; // When set, uses java -cp instead of java -jar
runtime?: string; // Runtime name override
}

Go Apps

Go apps build a command-line tool from source using the managed Go SDK. The lock file carries both go.mod and go.sum so the build is reproducible and hash-verified.

const apps = {
govulncheck: {
go: {
packageName: "golang.org/x/vuln/cmd/govulncheck",
version: "v1.3.0",
lockFile: "br:...", // brotli-compressed lock file (required)
runtime: "go-default", // optional runtime override
},
},
};

Go-specific fields:

interface AppConfigGo {
packageName: string; // Go import path, e.g. "golang.org/x/vuln/cmd/govulncheck"
version: string; // Module version query, e.g. "v1.3.0"
lockFile: string; // Brotli-compressed JSON {"mod","sum"} with "br:" prefix (required)
runtime?: string; // Runtime name override
}

The tool is built with go build -trimpath -mod=readonly in an isolated, hardened environment. See the Supply Chain Security guide for the full defense model.

Shell Apps

Shell apps wrap system commands. Set environment variables through the shared top-level env field.

const apps = {
"my-script": {
shell: {
name: "bash",
args: ["-c", "echo hello"],
},
env: { MY_VAR: "value" },
},
};

Shell-specific fields:

interface AppConfigShell {
name: string; // Command name
args?: string[]; // Default arguments
}

Bundles (bundles)

Bundles store static content (files, archives) in a hash-keyed cache directory and expose it through .datamitsu/ symlinks. Unlike apps, bundles are not executable.

interface Bundle {
version?: string;
files?: Record<string, string>;
archives?: Record<string, ArchiveSpec>;
links?: Record<string, string>;
}
FieldTypeDescription
versionstringVersion identifier (changes trigger cache invalidation)
filesRecord<string, string>Filename to content mapping
archivesRecord<string, ArchiveSpec>Named archives (inline or external)
linksRecord<string, string>Link name to relative path in install dir

A bundle must have at least files or archives. Link names must be unique across both apps and bundles.

Link values can point to files or directories within the install dir. Use "." to link to the entire bundle directory.

Example:

const bundles = {
"agent-skills": {
version: "1.0",
files: {
"agents.md": "# Agent instructions...",
"skills/search.md": "# Search skill...",
},
links: {
"agent-skills-dir": ".", // link to entire bundle directory
"agents-md": "agents.md", // link to a single file
},
},
};

Install path: {cache}/.bundles/{name}/{hash}/

See Managed Content (Bundles) for a full guide.

Runtimes (runtimes)

Runtimes define how language-specific package managers are provisioned.

interface RuntimeConfig {
kind: "node" | "uv" | "jvm" | "go";
mode: "managed" | "system";
managed?: RuntimeConfigManaged; // Required for managed mode
system?: RuntimeConfigSystem; // For system mode
node?: RuntimeConfigNode; // Required when kind is "node"
uv?: RuntimeConfigUV; // When kind is "uv"
jvm?: RuntimeConfigJVM; // Required when kind is "jvm"
go?: RuntimeConfigGo; // Required when kind is "go"
}

Managed Mode

In managed mode, datamitsu downloads the runtime binary itself:

const runtimes = {
"node-default": {
kind: "node",
mode: "managed",
managed: {
binaries: {
linux: {
amd64: {
glibc: {
url: "https://nodejs.org/dist/v26.2.0/node-v26.2.0-linux-x64.tar.xz",
hash: "abc123...", // SHA-256 (mandatory)
contentType: "tar.xz",
binaryPath: "node-v26.2.0-linux-x64/bin/node",
extractDir: true,
},
},
},
// ... other platforms
},
},
node: {
nodeVersion: "26.2.0",
pnpmVersion: "11.5.0",
pnpmHash: "def456...", // SHA-256 of pnpm package
},
},
};

System Mode

In system mode, the runtime uses the system-installed version:

const runtimes = {
"uv-system": {
kind: "uv",
mode: "system",
system: {
command: "uv",
systemVersion: "1.0", // Bump to invalidate cache
},
uv: {
pythonVersion: "3.12",
},
},
};

Runtime Kind Configuration

Node Runtime:

interface RuntimeConfigNode {
nodeVersion: string; // e.g., "26.2.0"
pnpmVersion: string; // e.g., "11.5.0"
pnpmHash: string; // SHA-256 of pnpm package (mandatory)
}

UV Runtime:

interface RuntimeConfigUV {
pythonVersion?: string; // e.g., "3.14.3"
}

JVM Runtime:

interface RuntimeConfigJVM {
javaVersion: string; // e.g., "25"
}

Go Runtime:

interface RuntimeConfigGo {
goVersion: string; // Go SDK version to build with, e.g., "1.26.3"
}

Tools (tools)

Tools define fix and lint operations that datamitsu executes.

interface Tool {
name: string;
operations: Partial<Record<"fix" | "lint", ToolOperation>>;
projectTypes?: string[]; // Restrict to specific project types
}

interface ToolOperation {
app: string; // App name from apps
args: string[]; // Supports template placeholders
globs?: string[]; // File patterns (doublestar syntax; `!` negation not supported). Omit to match all discovered files.
excludeGlobs?: string[]; // Patterns removed from the matched set (doublestar syntax)
scope: "repository" | "per-project" | "per-file";
batch?: boolean; // Batch files into single execution (default: true)
priority?: number; // Execution order (lower = first, default: 0)
invalidateOn?: string[]; // Files that invalidate cache
env?: Record<string, string>; // Extra environment variables
}

Example:

const toolsConfig = {
prettier: {
name: "prettier",
operations: {
fix: {
app: "prettier",
args: ["--write", "{files}"],
globs: ["**/*.{js,ts,jsx,tsx,json,md,yaml,yml}"],
scope: "per-project",
},
lint: {
app: "prettier",
args: ["--check", "{files}"],
globs: ["**/*.{js,ts,jsx,tsx,json,md,yaml,yml}"],
scope: "per-project",
},
},
projectTypes: ["typescript", "javascript"],
},
};

Scope Types

ScopeDescriptionWorking Directory
repositoryRuns once for the entire repositoryGit root
per-projectRuns once per detected projectProject root
per-fileRuns once per matched fileProject root

See Template Placeholders for the {file}, {files}, {root}, {cwd}, and {toolCache} placeholders available in args.

Project Types (projectTypes)

Project types define markers used to detect project boundaries in the repository.

const projectTypes = {
typescript: {
markers: ["package.json", "tsconfig.json"],
},
golang: {
markers: ["go.mod"],
},
python: {
markers: ["pyproject.toml", "setup.py"],
},
};

Config Init (init)

Config init entries define configuration files that datamitsu setup generates.

interface ConfigInit {
content?: (context: ConfigContext) => string;
deleteOnly?: boolean; // Only delete, don't create
linkTarget?: string; // Create symlink instead of writing content
otherFileNameList?: string[]; // Conflicting files to delete
projectTypes?: string[]; // Restrict to project types
scope?: "project" | "git-root"; // Where to create: "project" (default) or "git-root" (once at root)
}

The content function receives a context object:

interface ConfigContext {
cwdPath: string; // Current working directory
rootPath: string; // Git repository root
datamitsuDir: string; // Relative path from cwdPath to .datamitsu/
isRoot: boolean; // Is cwdPath the git root?
projectTypes: string[]; // Detected project types
existingContent?: string; // Previous layer's generated content (if any)
existingPath?: string; // Current file path (if exists)
originalContent?: string; // Unmodified content from disk
}

Example:

const init = {
"eslint.config.js": {
projectTypes: ["typescript", "javascript"],
content: (context) => {
const configPath = tools.Path.forImport(
tools.Path.join(context.datamitsuDir, "eslint.config.js"),
);
return `import config from "${configPath}";\nexport default config;\n`;
},
otherFileNameList: [".eslintrc", ".eslintrc.json", ".eslintrc.yml"],
},
};

Init Commands (initCommands)

Init commands run shell commands during datamitsu init.

interface InitCommand {
command: string; // App name from apps
args: string[]; // Command arguments
projectTypes?: string[]; // Restrict to project types
}

Example:

const initCommands = {
lefthook: {
command: "lefthook",
args: ["install"],
},
};

Archives

Apps can bundle directory trees via inline or external archives.

interface ArchiveSpec {
inline?: string; // Brotli-compressed tar: "tar.br:..." prefix
url?: string; // External archive URL
format?: string; // Required for external: "tar", "tar.gz", etc.
hash?: string; // SHA-256 required for external archives
}

Extraction order: Archives extracted first (sorted alphabetically), then files written (files overwrite archive contents). Package manager runs after both.

Archives are supported on UV apps, node apps, and bundles.

Ignore Rules

The ignoreRules field accepts .datamitsuignore-syntax rules:

const config = {
ignoreRules: ["vendor/**/*: *", "**/*.generated.go: golangci-lint"],
};

See Ignore Rules for the full syntax reference.

Shared Storage (sharedStorage)

A map[string]string field that flows through the config chain as ordinary JS input. Use it to pass arbitrary data between config layers that doesn't fit the typed config structure.

/// <reference path=".datamitsu/datamitsu.config.d.ts" />

// Setting values in a config layer
function getConfig(input) {
return {
...input,
sharedStorage: {
...input.sharedStorage,
"llms-txt": "# Project documentation...",
"feature-flag": "true",
},
};
}
globalThis.getConfig = getConfig;

// Reading values in a downstream config layer
function getConfig(input) {
const llmsTxt = input.sharedStorage?.["llms-txt"];
// Use the value...
return { ...input };
}
globalThis.getConfig = getConfig;

See Managed Content - Shared Storage for usage examples.

JavaScript APIs

The following APIs are available in configuration files.

Format Utilities

// YAML
YAML.parse(text);
YAML.stringify(value);

// TOML
TOML.parse(text);
TOML.stringify(value);

// INI
INI.parse(text);
INI.stringify(sections);
INI.toRecord(sections);

Path Utilities

// Join path segments
tools.Path.join("src", "components", "Button.tsx");

// Get absolute path
tools.Path.abs("relative/path");

// Get relative path (basePath defaults to git root)
tools.Path.rel(targetPath, basePath);

// Convert to ES module import path (ensures ./ or ../ prefix)
tools.Path.forImport(tools.Path.join(context.datamitsuDir, "eslint.config.js"));
// → "./.datamitsu/eslint.config.js"
// Get relative path from a file to a managed config link
tools.Config.linkPath("eslint", "eslint-config", fromPath);

Ignore Utilities

// Parse .gitignore-style content
const groups = tools.Ignore.parse(content);

// Stringify back with optional group ordering
const output = tools.Ignore.stringify(groups, groupOrder);

Platform Information

const info = facts();
// info.os → "linux", "darwin", "windows", etc.
// info.arch → "amd64", "arm64"
// info.libc → "glibc", "musl", "unknown" (Linux-only detection)
// info.isInGitRepo → true/false
// info.isMonorepo → true/false
// info.env → environment variables

Security Requirements

All artifacts downloaded from the internet must have a SHA-256 hash specified:

  • Binary apps: hash field on each platform entry
  • JVM apps: jarHash field
  • External archives: hash field
  • Node runtime (pnpm): pnpmHash field

Missing or empty hashes are treated as configuration errors.