Skip to main content

Core Concepts

datamitsu is built around five core concepts: binary management, runtime management, managed configs, the tooling system, and configuration layers.

Binary Management​

datamitsu downloads, verifies, and stores tool binaries per platform. Every binary must have a SHA-256 hash — datamitsu refuses to download anything without one.

Binaries are kept at ~/.cache/datamitsu/store/.bin/{name}/{configHash} and reused across runs. The internal store key is derived from the binary info and resolved target, so changing a version, hash, OS, architecture, or libc selects a fresh entry.

Supported archive formats include: tar.gz, tar.xz, tar.bz2, tar.zst, zip, and raw binaries.

App Types​

datamitsu supports seven types of applications:

TypeDescriptionExample Tools
binarySelf-managed binaries with URLs and hashesgolangci-lint, hadolint, shellcheck
bunnpm packages installed and run with Buneslint
uvPython packages via managed UV runtimeyamllint, ruff
nodenpm packages via managed Node.js + pnpmeslint, prettier, spectral
jvmJVM applications via managed JDKopenapi-generator-cli
goGo tools built from source via managed SDKgovulncheck
shellShell commands with custom environmentcustom scripts

Runtime Management​

For tools that need a language runtime (Bun, Python, Node.js, Java, or Go), datamitsu manages the runtime itself. This provides complete isolation — each app gets its own environment with pinned dependencies.

How Runtimes Work​

  1. Managed mode — datamitsu downloads the runtime binary (Bun, UV, Node.js, JDK, or Go SDK) with hash verification
  2. System mode — Uses a runtime already installed on your system

Each runtime-managed app gets an isolated directory at ~/.cache/datamitsu/store/.apps/{kind}/{app}/{hash}/. The internal key includes the effective runtime and app configuration, lock and managed-content inputs, and applicable target dimensions (OS, architecture, and libc), so a relevant change produces a fresh environment.

Runtime Types​

  • Bun — Downloads and verifies a pinned Bun archive, runs the shared pnpm installer with Bun, and executes JavaScript entrypoints with Bun
  • UV (Python) — Downloads UV, optionally pins a Python version, creates an isolated project environment with pyproject.toml + uv sync
  • Node (Node.js) — Downloads and verifies (SHA-256) a pinned Node.js archive and extracts it, downloads pnpm from the npm registry, runs pnpm install in isolated app directories
  • JVM (Java) — Downloads Temurin JDK, extracts the full JDK tree, downloads JAR files with hash verification, executes via java -jar
  • Go — Downloads and verifies (SHA-256) a pinned Go SDK, builds tools from source with go build -trimpath -mod=readonly against a go.mod + go.sum lock file

Lock Files​

Bun, Node, UV, and Go apps require lock files (pnpm-lock.yaml for both JavaScript runtimes, uv.lock, or a go.mod + go.sum payload). Normal config loading rejects a runtime-managed app without one. Lock content can be embedded compactly with brotli compression.

Generate a lock file:

datamitsu config lockfile <appName>

Managed Configs​

datamitsu can distribute configuration files from runtime-managed apps to your project via symlinks in a .datamitsu/ directory at your git root.

Apps declare what files they expose through Links:

"eslint-config": {
node: {
packageName: "@company/eslint-config",
binPath: "node_modules/.bin/eslint",
version: "1.0.0",
lockFile: "br:...",
},
links: {
"eslint-config": "dist/eslint.config.js",
},
}

After running datamitsu init, a symlink is created at .datamitsu/eslint-config pointing to the file inside the app's install directory. Your project configs can then reference it:

// eslint.config.ts
import config from "./.datamitsu/eslint-config";
export default config;

The tools.Config.linkPath() and tools.Path.forImport() JS APIs help generate correct relative paths in config files.

Tooling System​

datamitsu runs fix and lint operations on your code. Tools are configured with glob patterns, scope, and commands.

Scopes​

  • per-file — Tool runs once per matched file (e.g., hadolint {file})
  • per-project — Tool runs once per detected project in a monorepo (e.g., eslint {files})
  • repository — Tool runs once from git root (e.g., golangci-lint with scope: repository)

Operations​

const tools = {
eslint: {
name: "ESLint",
operations: {
fix: {
app: "eslint",
args: ["--fix", "{files}"],
scope: "per-project",
globs: ["**/*.{ts,tsx,js,jsx}"],
},
lint: {
app: "eslint",
args: ["{files}"],
scope: "per-project",
globs: ["**/*.{ts,tsx,js,jsx}"],
},
},
projectTypes: ["npm-package"],
},
};

Template Placeholders​

Tool arguments support placeholders that resolve at execution time:

PlaceholderResolves To
{file}Single file path (per-file scope)
{files}Separate arguments per file
{root}Git repository root
{cwd}Per-project working directory
{toolCache}Per-project, per-tool cache directory

Ignore Rules​

Use .datamitsuignore files to disable specific tools for matching file patterns:

vendor/**/*: golangci-lint, gofmt
*.generated.ts: eslint, prettier

Configuration Layers​

datamitsu loads configuration in layers, each receiving the previous result:

Each config file must export getMinVersion() (minimum datamitsu version, checked before loading) and getConfig(prev) (receives the previous layer and returns a new config). This enables inheritance and progressive customization while ensuring version compatibility.

Your git-root config can also export getBeforeConfigs() to declare local under-layers — the config-declared equivalent of --before-config. This lets a globally installed datamitsu load a shared wrapper config without the flag. It is skipped when --before-config is passed (the flag wins). See Configuration → Declared Before-Configs.

Remote Configs​

Any config can declare parent configs it inherits from:

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

function getRemoteConfigs() {
return [
{
url: "https://example.com/shared-base.ts",
hash: "sha256:abcdef1234567890abcdef1234567890abcdef1234567890abcdef12345678",
},
];
}
globalThis.getRemoteConfigs = getRemoteConfigs;

Remote configs require a SHA-256 hash (mandatory) and are cached locally; cache validity is determined by hash match (no TTL).

Monorepo Support​

datamitsu is designed for monorepos. It detects project boundaries by looking for markers like package.json, go.mod, Cargo.toml, and pyproject.toml.

Each project gets:

  • Isolated cache at ~/.cache/datamitsu/cache/projects/{hash}/cache/{projectPath}/{toolName}/
  • Scoped tool execution in the project's working directory
  • Independent configuration via managed config links

When running from a subdirectory, datamitsu restricts its scope to projects within that subtree.

Next Steps​