Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,21 @@ breaking entries are marked **BREAKING**.

## [Unreleased]

## [0.17.0] - 2026-08-31

### Changed
- **BREAKING: removed plan-side confirm-key redaction** — `PlannedValue::Redacted`,
`StatementPlan::presented_keys`, `strip_confirm_tokens`, and `redact_keys` are
gone. The credential they protected was removed in 0.14.0; `--confirm=<key>`
now plans and renders like any other argument.

- `ExecContext` carries `kill_grace` and `background_job`, so a tool holding only
an `ExecContext` can spawn a child with the kernel's external-command
discipline. `tools::DEFAULT_KILL_GRACE` is 2s. Only a struct literal changes.
- **BREAKING: `ExecContext` gained two fields and is now `#[non_exhaustive]`** —
it carries `kill_grace` and `background_job`, so a tool holding only an
`ExecContext` can spawn a child with the kernel's external-command discipline.
`tools::DEFAULT_KILL_GRACE` is 2s. A struct literal outside the crate no longer
compiles: build one with `ExecContext::new` or a `with_*` constructor and set
the fields you need. `#[non_exhaustive]` is the point — the next field the
kernel adds will not break you again.

- **Arithmetic diverges from bash on purpose** — overflow, an unset/empty
operand, and a leading zero are errors, never a wrap or 0; strings are
Expand All @@ -30,8 +36,9 @@ breaking entries are marked **BREAKING**.
path resolver for a backend rooted at a host directory: sync, std-only,
containment inside. `Follow::Final` follows the last component;
`Follow::LinkItself` acts on the link (remove, rename, lstat, symlink).
- **`kaish_vfs::conformance`** (`conformance` feature) — 19 symlink cases any
`Filesystem` backend runs against itself via `run_all(make_root)`.
- **`kaish_vfs::conformance`** (`conformance` feature) — 20 symlink cases a
`Filesystem` backend runs against itself via `run_all(make_root)`. LocalFs,
MemoryFs, and OverlayFs run them; DevFs is exempt, having no symlinks.
- **`[[ -L path ]]`** (alias `-h`) and `test -L` — true when the path is a
symlink, including a dangling one.
- **`cp -P`/`-L`**; `cp -r` recreates a symlink as a link with the same
Expand Down Expand Up @@ -86,6 +93,10 @@ breaking entries are marked **BREAKING**.
that says what to fix, including the validator's suggested rewrite. A
context that carries information, like `Failed to read script: <path>`,
stays.
- **The glued-argv error names the word that needs quoting** — `git show
HEAD:dir/x.py` blamed `show`, an innocent token three characters earlier.
The span now covers the whole pasted run, so the advice points at the word
it is about.
- **A comparison kaish cannot make is a fault, not `false`** — `[[ ]]`, `test`,
and `(( ))` now agree: exit 2 where nothing reads the result as a boolean, and
an abort where something does (`if`/`while`, `!`, the left operand of
Expand Down Expand Up @@ -2568,7 +2579,8 @@ Initial public release of **kaish** (会sh) — a predictable Bourne-like shell
- **REPL** (`kaish-repl`) with multi-line input, completion, and history; **MCP server** (`kaish-mcp`) exposing `kaish_execute` with help resources and structured + plain-text content blocks.
- **`KernelClient` trait** + `EmbeddedClient` for in-process embedding; topic-based help system; `kaish-wasi` `wasm32-wasip1` target.

[Unreleased]: https://github.com/tobert/kaish/compare/v0.16.0...HEAD
[Unreleased]: https://github.com/tobert/kaish/compare/v0.17.0...HEAD
[0.17.0]: https://github.com/tobert/kaish/compare/v0.16.0...v0.17.0
[0.16.0]: https://github.com/tobert/kaish/compare/v0.15.0...v0.16.0
[0.15.0]: https://github.com/tobert/kaish/compare/v0.14.1...v0.15.0
[0.14.1]: https://github.com/tobert/kaish/compare/v0.14.0...v0.14.1
Expand Down
20 changes: 10 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ members = [
]

[workspace.package]
version = "0.16.0"
version = "0.17.0"
edition = "2024"
rust-version = "1.85"
authors = ["Amy Tobey <tobert@gmail.com>"]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ Construct a `Kernel`, point it at a sandbox root, call `execute()`:

```toml
[dependencies]
kaish-kernel = "0.16"
kaish-kernel = "0.17"
tokio = { version = "1", features = ["full"] }
```

Expand Down
6 changes: 3 additions & 3 deletions crates/kaish-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ readme = "../../README.md"
# Feature-neutral on purpose: the embedder decides the kernel's feature set
# (kaish-web builds no-default for wasm; native hosts add localfs etc.).
# Unification means enabling defaults here would trample that choice.
kaish-kernel = { path = "../kaish-kernel", version = "0.16.0", default-features = false }
kaish-types = { path = "../kaish-types", version = "0.16.0" }
kaish-kernel = { path = "../kaish-kernel", version = "0.17.0", default-features = false }
kaish-types = { path = "../kaish-types", version = "0.17.0" }

# Async traits only — no runtime: the library spawns nothing itself, and a
# tokio dep here would drag net/mio into wasm builds (kaish-extras).
Expand All @@ -39,7 +39,7 @@ tracing = { workspace = true }
# this, `cargo test -p kaish-client` alone sees a no-localfs kernel while a
# whole-workspace run gets localfs unified in by the REPL, and outcomes
# depend on which crates happened to build.
kaish-kernel = { path = "../kaish-kernel", version = "0.16.0", features = ["localfs"] }
kaish-kernel = { path = "../kaish-kernel", version = "0.17.0", features = ["localfs"] }
proptest = { workspace = true }
tempfile = { workspace = true }
# Tests drive the async client API; the library itself needs no runtime —
Expand Down
2 changes: 1 addition & 1 deletion crates/kaish-help/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ categories.workspace = true
readme = "../../README.md"

[dependencies]
kaish-types = { path = "../kaish-types", version = "0.16.0" }
kaish-types = { path = "../kaish-types", version = "0.17.0" }

[lints]
workspace = true
12 changes: 6 additions & 6 deletions crates/kaish-kernel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ readme = "../../README.md"
exclude = ["tests/snapshots/"]

[dependencies]
kaish-glob = { path = "../kaish-glob", version = "0.16.0" }
kaish-types = { path = "../kaish-types", version = "0.16.0", features = [] }
kaish-help = { path = "../kaish-help", version = "0.16.0" }
kaish-tool-api = { path = "../kaish-tool-api", version = "0.16.0" }
kaish-vfs = { path = "../kaish-vfs", version = "0.16.0", features = ["memory", "overlay"] }
kaish-glob = { path = "../kaish-glob", version = "0.17.0" }
kaish-types = { path = "../kaish-types", version = "0.17.0", features = [] }
kaish-help = { path = "../kaish-help", version = "0.17.0" }
kaish-tool-api = { path = "../kaish-tool-api", version = "0.17.0" }
kaish-vfs = { path = "../kaish-vfs", version = "0.17.0", features = ["memory", "overlay"] }

# Async runtime — minimal base; `localfs` adds tokio/fs, `subprocess` adds
# tokio/process + tokio/rt-multi-thread (see [features]).
Expand Down Expand Up @@ -90,7 +90,7 @@ jaq-json = { workspace = true }
# Optional deps, each pulled in by its capability feature:
# kaish-tools-host → host, trash/directories → os-integration,
# tiktoken-rs → tokens.
kaish-tools-host = { path = "../kaish-tools-host", version = "0.16.0", optional = true }
kaish-tools-host = { path = "../kaish-tools-host", version = "0.17.0", optional = true }
trash = { workspace = true, optional = true }
directories = { workspace = true, optional = true }
tiktoken-rs = { workspace = true, optional = true }
Expand Down
2 changes: 1 addition & 1 deletion crates/kaish-kernel/src/ast/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub struct PlannedStatement {
/// gaps: `plans[i].index == i`, always. Indexing the list by this number
/// reads the statement it names.
pub index: usize,
/// What the statement was asked to run, with every credential redacted.
/// What the statement was asked to run.
pub plan: Plan,
}

Expand Down
5 changes: 5 additions & 0 deletions crates/kaish-kernel/src/tools/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ pub(crate) enum ExternalCommandOutcome {
///
/// Provides access to the backend (for file operations and tool dispatch),
/// scope, and other kernel state.
///
/// Build one with [`ExecContext::new`] or one of the `with_*` constructors and
/// set the fields you need. The struct is `#[non_exhaustive]`, so the kernel can
/// add a field without breaking an embedder that never asked for it.
#[non_exhaustive]
pub struct ExecContext {
/// Kernel backend for I/O operations.
///
Expand Down
6 changes: 3 additions & 3 deletions crates/kaish-repl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ path = "src/main.rs"
[dependencies]
# The REPL is the full interactive human shell: it needs every capability
# (external commands + job control, git, host introspection, tokens, trash).
kaish-kernel = { path = "../kaish-kernel", version = "0.16.0", features = ["full"] }
kaish-client = { path = "../kaish-client", version = "0.16.0" }
kaish-types = { path = "../kaish-types", version = "0.16.0" }
kaish-kernel = { path = "../kaish-kernel", version = "0.17.0", features = ["full"] }
kaish-client = { path = "../kaish-client", version = "0.17.0" }
kaish-types = { path = "../kaish-types", version = "0.17.0" }

# Line editing
rustyline = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion crates/kaish-tool-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ categories.workspace = true
readme = "../../README.md"

[dependencies]
kaish-types = { path = "../kaish-types", version = "0.16.0", features = [] }
kaish-types = { path = "../kaish-types", version = "0.17.0", features = [] }

async-trait = { workspace = true }
clap = { workspace = true }
Expand Down
4 changes: 2 additions & 2 deletions crates/kaish-tools-host/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ categories.workspace = true
readme = "../../README.md"

[dependencies]
kaish-types = { path = "../kaish-types", version = "0.16.0", features = [] }
kaish-tool-api = { path = "../kaish-tool-api", version = "0.16.0" }
kaish-types = { path = "../kaish-types", version = "0.17.0", features = [] }
kaish-tool-api = { path = "../kaish-tool-api", version = "0.17.0" }

async-trait = { workspace = true }
clap = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion crates/kaish-vfs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ categories.workspace = true
readme = "../../README.md"

[dependencies]
kaish-types = { path = "../kaish-types", version = "0.16.0", features = [] }
kaish-types = { path = "../kaish-types", version = "0.17.0", features = [] }
async-trait = { workspace = true }
# DevFs's /dev/urandom pulls from the OS CSPRNG. Pure (no tokio); works on
# Unix/macOS/WASI.
Expand Down
6 changes: 3 additions & 3 deletions docs/EMBEDDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ and output capture.

## Stability

kaish is pre-1.0 (currently 0.16.x, MSRV 1.85). The language has settled;
kaish is pre-1.0 (currently 0.17.x, MSRV 1.85). The language has settled;
the embedding API may still change between minor versions where it improves
both kaish and its embedders — [kaijutsu](https://github.com/tobert/kaijutsu)
is the reference embedder. Pin a minor version and read release notes when
Expand Down Expand Up @@ -1172,7 +1172,7 @@ PY"
"redirects":[{"kind":"<<","target":{"plain":"'PY'"}}],"background":false,
"heredocs":[{"index":0,"delimiter":"PY","literal":true,"strip_tabs":false,
"body":{"plain":"import os\n"},"body_offset":15}]}]}}],
"kaish_version":"0.16.0","kaish_git_hash":"b27ea4dd","kaish_build_date":"2026-08-23"}
"kaish_version":"0.17.0","kaish_git_hash":"4d02cd6b","kaish_build_date":"2026-08-31"}
```

**Nothing executes and no kernel is built** — planning is a pure function of the
Expand All @@ -1182,7 +1182,7 @@ source text, so it touches no filesystem and needs no capability feature.
The output is always a JSON object, so a caller parses one shape whatever
happened: `{"statements": [...]}` and exit **0**, or `{"errors": [...]}` and
exit **2** — the same usage code a builtin returns for bad argv. Both shapes
also carry `kaish_version` (bare semver, e.g. `"0.16.0"`), `kaish_git_hash`
also carry `kaish_version` (bare semver, e.g. `"0.17.0"`), `kaish_git_hash`
(short hash, or `"unknown"` when kaish was built with no `.git` present — a
crates.io tarball build, for instance), and `kaish_build_date`
(`YYYY-MM-DD`) at the top level, so a caller windowing measurements by
Expand Down
7 changes: 4 additions & 3 deletions docs/LANGUAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1057,9 +1057,10 @@ echo $((2#$bits)) # a string of binary digits

### Variables and expansions

A variable name may omit the `$`. An integer works directly; `true` is 1 and
`false` is 0; a string holding one number in any spelling above is read as
that number.
A variable name may omit the `$`. An integer works directly; a variable holding
`true` reads as 1 and `false` as 0; a string holding one number in any spelling
above is read as that number. A bare `true` is a variable name, not a literal —
`$(( true + 1 ))` names `true` as unset unless you set it.

```sh
count=4
Expand Down