Skip to content

v0.2.4

Choose a tag to compare

@github-actions github-actions released this 25 Aug 05:08
· 67 commits to main since this release

Noah Code v0.2.4

This release is a security and reliability hardening pass across the permission engine, checkpoint
capture, workspace edits, budgets, and the terminal interface, plus dependency and CI updates.

Security

  • Closed a hard secret-deny bypass through Git object syntax: git show HEAD:.env (and :path
    forms generally) is now classified by the path component and denied like cat .env, in build,
    plan, and --auto modes alike.
  • Unscoped patch-output Git commands (git log -p, bare git show/git diff) no longer ride the
    read-only auto-allow bump; they ask, since they can dump committed secrets without naming a path.
  • Expanded secret classification to common credential stores: .npmrc, .pypirc, .netrc,
    .pgpass, .envrc, .kube/config, .docker/config.json, .aws/credentials, and Java/JCEKS
    key stores.
  • Joined short-flag values are now scanned as paths, so grep -f/etc/passwd, rg -f.env, and
    tail -F~/log can no longer evade the external-path and secret checks.
  • Git checkpoint capture no longer stages secret-classified paths into refs/noah-code/checkpoints/*
    and no longer executes repository clean filters — capture uses filter-free plumbing
    (hash-object --no-filters + update-index --cacheinfo), preserving executable bits and storing
    symlinks as links.
  • Non-interactive noah run --auto now rejects elevated-risk commands (file removal, downloads,
    find -delete/-exec, and similar) instead of silently approving them; interactive behavior is
    unchanged.
  • Plan mode can no longer be crossed without confirmation: mode/model front matter in
    repository custom commands is ignored (user commands keep it), and plan.exit_to_build() is
    never auto-approved.
  • find -delete/-exec/-execdir joined the elevated-risk floor, and rg --hostname-bin is no
    longer treated as read-only.

Reliability and correctness

  • The main edit path (replace/edit) is now atomic and newline-preserving: byte-level splice,
    exactly-one-match enforcement, and temp+fsync+rename writes — CRLF files no longer flip to LF
    when one hunk changes, and a crash mid-edit cannot leave a truncated file.
  • Reads are bounded: whole-file reads above max_file_bytes require an explicit line range, ranged
    reads stream instead of loading the file, binary files fail cleanly, and durable pre-images above
    undo_blob_limit degrade to hash-only instead of ballooning the session database.
  • Background-job durable logs rotate at 4 MB keeping the newest lines, and log paging tail-reads
    instead of loading the whole file.
  • Live model switches (/model, /reasoning, /providers use) now rebuild the full retry and
    fallback pipeline — switches no longer silently drop transient retries and fallback models.
  • The WAIT path can no longer hang: background-job terminal events always fire even if the runtime
    write fails, and the host wait is bounded with state re-checks; a job finishing between WAIT and
    wake no longer fails the run spuriously.
  • Cost budgets work: per-response cost is recovered from provider-reported cost or LiteLLM's
    pricing table, so max_cost_usd enforces real charges and /tokens reports real cost instead of
    $0.000000.
  • Ctrl+C under asyncio.run exits cleanly with the designed double-press flow instead of a
    traceback; one press at an idle prompt hints, a second exits, and mid-turn cancellation renders
    once.
  • Configuration is validated strictly: unknown keys and invalid values or TOML fail every command
    with a one-line error naming the file and field — no more tracebacks from noah doctor.
  • noah run no longer exits 0 without doing anything when an auto-update installs; non-interactive
    runs print the update notice and proceed.
  • Fixed atomic-patch rollback ordering (fsync failure no longer strands a renamed file), new-file
    permissions (umask default instead of 0600), grep-harvested edit anchors after cd,
    stale-anchor detection without a prior read, double-close() wiping the undo journal, stale
    interrupted runs resurrecting, and checkpoint metadata clobbering newer session metadata.

Interface

  • Fixed priority keybindings that hijacked basic editing keys: Skills picker moved to Ctrl+G,
    return-to-live moved to Ctrl+], and End/Ctrl+K work normally inside the composer again.
  • Cmd+C/Ctrl+C in the composer copies the composer's own selection; keyboard (shift-arrow)
    selections are copyable.
  • Transcript selection keeps the original message text instead of copying rendered soft wraps,
    padding, or transformed Markdown, with a high-contrast selection highlight across themes.
  • Ctrl+C now copies active selections from the transcript, composer, and single-line fields;
    Ctrl+V/Cmd+V reads the native system clipboard asynchronously in every editable field.
  • Native clipboard helpers are preferred over duplicate OSC 52 writes, and rapid copies are
    coalesced to prevent terminal flicker, UI stalls, and stale writes finishing out of order.
  • @-mention suggestions no longer rescan the whole workspace per keystroke: directory pruning
    plus a short-lived cache keep the composer responsive in large repositories.
  • One Ctrl+C now renders a single "turn cancelled" entry, and question-modal "Other" collects a
    free-text answer instead of submitting the literal string other.

Packaging and CI

  • LiteLLM re-pinned to >=1.96.0,<1.99.0 (resolved 1.98.0): upstream restored macOS wheels, so
    provider and security fixes from 1.92–1.98 now reach installs.
  • Added upper bounds for end-user installs (textual, pydantic, click, rich, PyYAML,
    packaging), which resolve fresh and ignore uv.lock.
  • Unified the duplicated dev-dependency declarations into the single dev extra.
  • The default test suite is now hermetic by construction (pytest-socket blocks network sockets);
    CI runs on v* tags, type-checks in the release pipeline, collects macOS coverage, and runs the
    network integration tests as a non-blocking job.
  • Expanded the hermetic suite to 582 passing tests.

Upgrade

Existing managed installations can run:

noah update

New installations can use the one-command installer from the README.

Full changelog: v0.2.3...v0.2.4