# Changelog
## 0.24.0 — 2026-09-09
- Release 0.24.0
## 0.23.0 — 2026-09-09
- Release 0.23.0
## 0.22.0 — 2026-09-09
- Release 0.22.0
## 0.21.0 — 2026-09-03
- Release 0.21.0
## 0.20.0 — 2026-09-03
- Release 0.20.0
## 0.19.0 — 2026-08-25
- Release 0.19.0
## 0.18.0 — 2026-08-22
- Release 0.18.0
## 0.17.0 — 2026-08-18
- Release 0.17.0
## 0.16.0 — 2026-08-16
- Release 0.16.0
## 0.15.0 — 2026-08-14
- Release 0.15.0
## 0.14.0 — 2026-08-13
- Release 0.14.0
## Unreleased
### Added
- `jan ps`: list jan processes (and descendants) with per-process and
collective CPU usage (`--jan-only`, `--avg`). See `docs/cli/ps.md`.
- `jan cron install` / `uninstall`: managed user-crontab block that runs
`jan --no-log cron` every minute (BEGIN/END JAN CRON markers; idempotent).
- `jan cron --list` prints each schedule plus the next fire in absolute local
time and a relative span (`--at` sets the list base minute).
- Optional `config:` on any command node and `jan config` with `emit`, `link`,
`unlink`, `apply`, and `deps`. `emit` concatenates `config.shell` fragments
(path or inline) for sourcing; `link` symlinks (or `--copy`) path sources or
writes inline bodies into `$HOME` / `$XDG_CONFIG_HOME`; `unlink` removes only
destinations that still match managed content; `apply` runs `config.apply`
argv lists; `deps` reports missing `config.deps` host tools. Config-only
nodes appear in `--help`. See `docs/cli/config.md`.
- Subcommand `--help` lists that node's `aliases:` and, when present, a
**Host configuration (`jan config`)** section for that node's `config:`
(shell path/inline, links, apply counts). Nodes with `run`, `aliases`, or
`config` (including alias-/config-only children) appear in the parent
subcommand list. Extra jan names show as "same as `jan … run`".
- Optional `aliases:` on any command node. `jan alias` emits extra names
for that node's `run` / leaf exec (`aliases: [lb]`) and traditional
shell aliases from a map (`gs: git status`). Empty map values are extra
jan names. Jan command names win on collision; skipped shell aliases are
noted as comments. Unsafe names fail at spec load.
### Changed
- `jan config link` skips destinations that already exist: it prints a warning
and continues (use `--force` to replace). An existing symlink to the intended
source is treated as already linked. `config.link` values may be inline file
bodies (written to the destination) or relative paths (symlinked / `--copy`).
Each `link` / `unlink` run prints a summary (created/already ok/skipped, or
removed/absent/foreign).
- `packages.gradle` for JVM/Kotlin script deps: inline
`group:artifact:version` lists or a `project:` directory with
`build.gradle(.kts)` + `gradle.lockfile`. Envs are hash-keyed under
`~/.cache/jan/packages/gradle/<hash>/`; Gradle resolves jars into `lib/`
(Java Library plugin / `runtimeClasspath`) and jan injects `CLASSPATH` plus
automatic `-cp` for `java` / `kotlin` / `kotlinc` argv.
Warm hits skip spawning `gradle`.
- Per-manager language/runtime minima on package decls: `packages.uv.python`,
`packages.pnpm.node`, and `packages.gradle.java` (alias `jdk`). Forms like
`21` or `>=3.11` are checked against the host toolchain on ensure/run and
included in the env hash. Map form uses `packages:` for the dependency list
(short list form unchanged).
- `exec.kotlin` for `.kt` / `.kts` leaves (path or inline): compile-once into the
package cache, wire gradle classpath, forward `exec.argv` to `main`.
- `exec.python` for `.py` leaves (path or inline via `python3 -c`) and `exec.node`
for `.js` / `.mjs` / `.cjs` (path or inline via `node -e`). `exec.argv` is
forwarded as script args; CLI string eval (`argv: [python3, -c, …]` /
`[node, -e, …]`) still works alongside these forms.
- `exec.bash` / `exec.sh` / `exec.zsh` for shell leaves (path or inline).
Inline Bash uses `bash -lc`, Zsh `zsh -c`, POSIX sh `sh -c`, with `$0`
inserted so `$1` / `"$@"` match script semantics. `argv: [bash, -lc, …]`
still works.
- Optional `tests:` on any command node: Given/When/Then POSIX `sh` cases
(`given_…_when_…_then_…` names). `jan test <path>` runs that node and every
nested descendant. `when:` is extra argv for the command the test is declared
on (the script path is implied); omit it to invoke that command with no extra
args. Captured into `JAN_STATUS` / `JAN_STDOUT` / `JAN_STDERR` for `then`.
Result lines print the script path and the test name. `jan test` never writes
the audit log (`--no-log` is implied, including nested `jan` invocations).
- `exec.text` (alias `exec.cat`) prints a literal YAML block with no
subprocess. `commands.help` leaves using this form are inlined into
`--help` (and omitted from the subcommand list), like `run` is the
conventional exec child.
- Optional `type:` and `choices:` on `inputs:` entries. jan checks values
(and non-empty defaults) before interpolating `${{ inputs.* }}` into
`exec.argv` / `env`. Types include `url`, `https`, `int`, `uint`, `float`,
`bool`, `path`, `file`, `dir`, `port`, `pid`, `email`, `hostname`, `ipv4`,
`ipv6`, `ip`, `uuid`, `hex`, `duration`, `date`, `json`, and `enum`.
Unknown types fail at spec load; bad CLI values fail before the script runs.
- `packages.pnpm` is implemented: inline `name@version` lists or a `project:`
directory with `package.json` + `pnpm-lock.yaml`. Envs are hash-keyed under
`~/.cache/jan/packages/pnpm/<hash>/` and installed there (never in your tree);
on run jan prepends `node_modules/.bin` to PATH, sets `NODE_PATH`, and
resolves argv[0] from `.bin`.
- `jan packages` built-in for inspecting cached package environments:
`list` / `show` / `path` for uv, pnpm, and gradle (`--lib` / `--classpath`
for gradle). `--json`, `--orphans`, and `--uv` / `--pnpm` / `--gradle`
scoping. `prune` drops orphaned envs older than a threshold (default 30d),
with optional `--min-size`, `--all`, and `--yes` (dry-run otherwise).
Successful runs update `.jan-used` so prune keeps hot caches.
### Changed
- Warm `packages.uv` / `packages.pnpm` / `packages.gradle` hits skip spawning
the manager `--version`; the tool is only required when an env must be built
or rebuilt. Cold `packages.gradle` resolves stream Gradle's console output and
print jan progress lines on stderr (coordinates, cache path, jar count).
- Package dependencies must pin an exact version so env hashes identify a single
resolution. uv: inline entries need `==` / `===` (rejected at load),
requirements files are checked line by line (no `-r` / `-e`), and `project:`
requires a `uv.lock`. pnpm: inline entries need a full
`name@major.minor.patch` (no ranges, dist-tags, aliases, or git/file specs),
and `project:` requires a `pnpm-lock.yaml` installed with `--frozen-lockfile`.
gradle: inline entries need `group:artifact:version` with an exact version
(no `+`, Ivy ranges, or `latest.release`), and `project:` requires a
`gradle.lockfile`. Locked uv projects now install from the exported lock plus
`uv pip install --no-deps <project>` instead of re-resolving.
## 0.13.0 — 2026-08-07
- Release 0.13.0
## 0.12.0 — 2026-08-07
### Added
- Advanced include links: local includes stay unhashed by default; optional
`sha256` pins verify on load and in `jan validate`.
- Script-file includes (non-`.yaml`/`.yml`) become exec leaves, with optional
`argv` / `passthrough` on the include map; include identity is retained on
the node for `jan show` / bundle closure.
- Local `exec.file` (optional `sha256`), mirroring remote `exec.url`.
- `jan bundle` packs linked script files alongside YAML.
- `packages.uv` for script package deps: inline list, `project:`, or
`requirements:`; hash-keyed venvs under `~/.cache/jan/packages/uv/`.
`packages.pnpm` is reserved (rejected until implemented).
- Release 0.12.0
## 0.11.0 — 2026-08-06
### Added
- Remote jan trees: `jan use https://…/bundle.zip --sha256 <hex>` downloads a
bundle, verifies the zip and `manifest.json` member hashes, unpacks under
`~/.cache/jan/trees/<sha256>/`, and prefers that directory.
- Remote YAML `include:` entries with required `url` + `sha256` (optional `ttl`).
- Remote script leaves via `exec.url` + `exec.sha256` (optional interpreter
`argv` prefix and `ttl`), using the same HTTPS fetch / SHA256 / TTL cache as
wgex-inspired object storage under `~/.cache/jan/objects/`.
- `JAN_ALLOW_HTTP` / `--allow-http` to override HTTPS-only defaults.
### Security
- Remote content still executes with the user's privileges once preferred or
included; hashes provide integrity, not publisher authentication.
- `jan bundle` fails if the tree contains remote includes (bundles stay
self-contained).
## 0.10.0 — 2026-08-06
- Release 0.10.0
## 0.9.0 — 2026-08-06
- Release 0.9.0
## 0.8.0 — 2026-08-06
- Release 0.8.0
Entries describe behavior at the time of each release and are not current usage
instructions. See [README.md](README.md) for the supported interface.
## Unreleased
### Added
- Built-ins `jan list`, `search`, `show`, `validate`, and `audit` for inspecting
the preferred tree and SQLite invocation log (semantic replacement for the
retired `scripts-cli`).
### Changed
- Personal utilities are no longer nested under `jan-cli/generated/scripts/`.
Prefer a flat tree such as `dotfiles/jan`. The old
`generate_scripts_jan_spec.py` helper is retired.
- Removed the incubator `scripts` project dependency (`scripts/source`).
### Breaking
- Spec selection now uses only `jan use <DIR>`. Removed direct spec flags,
spec-selection environment variables, cwd discovery, and well-known-directory
fallback behavior.
- `jan alias` now emits bare `jan` command chains without embedded spec flags.
### Security
- Confined YAML includes to the preferred tree; hardened alias generation and
bundle extraction; resolved executables before applying spec PATH entries.
- Documented that preferred trees are unsandboxed executable code and bundle
manifest hashes do not authenticate publishers.
## 0.7.0 — 2026-08-04
- Release 0.7.0
## 0.6.0 — 2026-08-04
- Release 0.6.0
## 0.5.0 — 2026-08-04
- Release 0.5.0
## 0.4.0 — 2026-08-04
- Release 0.4.0
## 0.3.0 — 2026-08-04
- Release 0.3.0
## 0.2.0 — 2026-06-03
### Breaking
- Removed the bundled embedded default spec (`default.spec.yaml` compiled into
the binary). At the time of this release, `jan` loaded specs from explicit
flags, cwd-local files, or the well-known install directory. Those resolution
modes were removed after 0.7.0; current versions use `jan use`.
### Added
- Added, at that time, a well-known spec directory and related environment
overrides. These interfaces are historical and no longer supported.
- Script `path`, `dependencies`, `requires`, and `env` fields for PATH prepending, transitive script deps, external tool checks, and environment variables.
- `jan bundle` and `jan alias` built-ins for portable spec export and shell alias generation.
### Changed
- Example default command tree moved to `examples/default.spec.yaml` (install manually or via `jan bundle` / `jan-install.sh`).
- Used the now-removed direct flags, environment variables, cwd lookup, and
well-known-directory fallback for spec resolution.
## 0.1.0
- Initial release with embedded default spec, YAML command trees, SQLite audit log, and extra-spec merging.