Skip to content

v0.0.2

Choose a tag to compare

@rstalets rstalets released this 01 Aug 06:21
d0605fc

choom v0.0.2 — release notes draft

Milestone: v0.0.2 — 9 issues closed, 0 open.

v0.0.1 shipped a workspace you could capture into. v0.0.2's headline is /ai: you can now call
your AI assistant from inside a document, without leaving the editor
— which is the whole premise
of this project arriving as an actual feature rather than a design goal. Around it, the release is
about what happens after capture: records can point at each other, tasks grew a body and can be
captured mid-sentence, and the whole TUI was re-laid-out around reading only what's on screen. The
project also picked up a new name.


Local AI assistant invocation (/ai)

user-visible · #19 · PR #34

choom has always been built on the assumption that a local AI assistant is reading the workspace.
This is the release where that assumption pays off from the inside: typing /ai <prompt> on its own
line in the editor and pressing enter saves the document, hands the prompt to whichever assistant
CLI you already have installed — Claude Code or GitHub Copilot — and drops the reply where the
command was. No integration, no API key, no second window.

  • While it runs the command line shows , the editor is read-only, and the status bar shows a
    randomly chosen corporate-jargon breadcrumb plus ctrl+c to cancel.
  • Every failure restores the line exactly as typed — cancelled, non-zero exit, empty reply, no
    assistant resolvable — each with a status-bar message naming the problem. A save failure is
    reported and the assistant is never invoked.
  • /ai is only a command when the line is entirely a command. Did you know you can type /ai in choom?, indented lines, /aim, and //ai are all plain text, never an error.
  • With exactly one supported assistant on PATH and nothing configured, /ai works with zero
    setup. With two or none, the status bar names /config assistant as the way to choose. A
    workspace with neither installed keeps every other feature unchanged.
  • Each assistant is invoked with a read-only permission flag (--allowedTools "Read" for Claude
    Code, --allow-tool "read" for Copilot) so it can read the document it was pointed at. Nothing
    beyond Read is granted.
  • New config surface: choom config assistant [<claude|copilot|none>] [--json] (get or set,
    reporting configured value, resolved value, source, and what's detected on this machine),
    choom init --assistant <value>, and /config assistant <value> in the TUI command bar —
    effective for the next /ai immediately, no restart. Stored as [assistant].name in
    .choom/config.toml; absent means "detect".
  • One deviation from the issue as written: choom init does not prompt. The constitution
    forbids the CLI blocking on input, so the choice is an init argument, with /config assistant
    as the interactive path.

It also shipped the reusable in-editor command framework (core.editor_commands) that /task and
/link were both built on later in this same release — a second, separate command grammar from the
list screen's command bar, where a line is a command only when it is entirely a command.

The project is now called choom

user-visible · #42 · PR #54

endpaper became choom. In Cyberpunk 2077 slang a choom is a good friend, which is the idea:
a tool that has your back, keeping you organized and your AI fed with context in a
corpo-restricted world.

  • The CLI command is choom (was endpaper), and the PyPI distribution is choom — reinstall
    with uv tool install choom.
  • Breaking: the workspace marker directory moved from .endpaper/ to .choom/. An existing
    workspace keeps working after mv .endpaper .choom from its root. Nothing else about a
    workspace's layout, frontmatter, or file contents changes.

Document links

user-visible · #27 · PR #40

Any record can now point at any other, and the workspace stays plain markdown while doing it. A
link is an ordinary CommonMark inline link, [text](path#id): the #id fragment is authoritative
and permanent, while the path is derived — computed by choom from the two real file locations, and
repaired whenever it goes stale.

  • Hand-writable. Write [Q3 planning](#meeting_20260728_a1b2c3d4) with no path at all and the
    correct relative path appears on the next save. Move the target and the path is corrected the
    same way. Nobody has to count ../.
  • Nothing is indexed. Inbound links are computed by scanning on demand — measured at 155 ms
    across 6,000 documents (50 MB) against a 500 ms budget, which is why there is no index and
    nothing is written back into a link's target.
  • New CLI surface. choom links <id> [--json] [--direction out|in|both] answers what a record
    points at and what points at it. choom links check reports stale (fixable) and dead
    (needs a decision) as two distinct classes; choom links heal [--dry-run] repairs every stale
    link and touches no dead one.
  • In the TUI. /link <search terms> on its own line in the editor becomes a correct markdown
    link to the one matching record; zero or several matches leave the line alone and report in the
    status bar. b toggles a Links pane in both the full-screen preview and the list screen's
    preview pane — outbound above, inbound below, enter/o to open. Clicking a rendered link
    opens the record rather than a browser.
  • Task lines gained a links: field, shaped exactly like tags: — comma-separated ids, never
    paths. Field order is now id, type, tags, links, created; a task with no links renders
    exactly as before.
  • Breaking: id prefixes are now the full collection name — meeting_, note_, task_
    instead of m_, n_, t_ — so a new collection never needs a registry of abbreviations. Ids
    written under the old scheme keep resolving; nothing is migrated and no existing file is
    rewritten.

Inline task capture

user-visible · #21 · PR #45

Most followups are born mid-sentence. Typing /task <description> (or /task.<type> ...) on its
own line in the editor and pressing enter now captures a task without leaving the document: the
line becomes a checklist item linking to it —
- [ ] [call Terry about the renewal](../../../tasks.md#task_a1b2) — cursor at its end, nothing
else on screen moving. #tag tokens are extracted exactly as the command bar already does, and
prefixing an existing line with /task.followup promotes that line's own words into the task.

The checklist item is a control surface, not a copy. Tick it and save, or tick the task from
the tasks list, and the other side follows. Opening a document reconciles every mirror in it
against tasks.md first, so nothing shown is ever stale — no repair command, no background
process, and no cost for a document with no mirrors. A mirror is found by its #task_id fragment
alone, so rewording the link text or reindenting the line never loses it. Genuine disagreement is
reported rather than silently resolved: a mirror and task that both changed since they last agreed
surfaces a conflict, two disagreeing mirrors leave tasks.md untouched for that task, and a
mirror whose task no longer exists is left alone and reported.

Completing a task from the tasks list splices every mirror in the documents it links to without
stamping those documents' updated — ticking a box in a different collection is not an edit to
the meeting note.

  • choom task add "<description>" --link <id> (repeatable) records the same relationship from the
    command line, validated before anything is written: an unresolvable id exits 1 and creates
    nothing.
  • choom task done/undone --json gain documents_updated and warnings. A document that
    couldn't be updated is a warning on stderr, never a non-zero exit — the task's own completion
    already succeeded.

Task content editing

user-visible · #26 · PR #36

A task can now carry an optional markdown body — the detail, or a running log ("07-28 called, left
voicemail"), that a single checkbox line couldn't hold.

  • Highlighting a task renders its body in the preview pane, the same way notes and meetings
    already do; a task with no body clears the pane instead of showing the previous task's content.
  • e on a highlighted task opens the editor scoped to that body alone (previously a no-op) —
    empty for a task with none, pre-filled for one that has one. ctrl+o/ctrl+x save, esc
    discards with the existing confirm-only-if-dirty rule. A save that changes nothing writes
    nothing. space (done/undone) leaves the body untouched.
  • On disk: indented continuation lines directly beneath the checkbox line in tasks.md — no
    sidecar file, no second store. One blank line separates them so the file stays valid CommonMark.
    Indentation is dedented for display and re-applied on write using whatever prefix was observed.
    A checkbox line indented under a task is still read as its own task, which is what keeps an
    existing vault's task list unchanged on upgrade — and is the one deliberate limit (no nested
    checklist inside a body).
  • choom task show <id> [--json] prints one task and its body: the same columns task list
    prints, then the body verbatim after a blank line. Exit codes 0 found, 1 unknown id, 2
    ambiguous id (names the conflicting lines), 3 no workspace. task list --json gains a body
    key on every entry; every existing key keeps its name and meaning.

UI layout refresh

user-visible · #17 · PR #30

The whole TUI was re-laid-out, and the reading model changed underneath it — the app now reads only
the month it is showing instead of scanning a whole collection.

  • Top collection bar. Choom >> Tasks Notes Meetings replaces the vertical collection
    menu; tab/shift+tab cycle and the panes refill immediately with focus on the list. The 14
    columns the old menu used go back to the list/preview split, and the bar degrades to a compact
    one-letter form on narrow terminals. The tool now opens on Tasks (was Meetings).
  • Month-scoped reading. For Notes and Meetings the left pane is a month list (YYYY-MM,
    most-recent-first, plus Unfiled for anything outside the YYYY/MM layout). Opening a
    collection or moving months reads only that month from disk.
  • Tasks: To-Do / Done in the left pane; the hidden a show-all binding is retired in favour
    of selecting Done directly.
  • Editor-first. e opens the editor straight from the list, and creating a note, meeting, or
    daily note lands in the editor rather than a read-only preview.
  • Command bar. The / prefix is permanent and can't be deleted. filter (alias f) is now
    an explicit verb — bare words are no longer silently treated as a search, and an unrecognised
    first word is a visible unknown command: '<word>'. An active filter searches every month, not
    just the displayed one, reading each month at most once per session.
  • /help opens a pane listing every command and key binding without leaving the list screen,
    and the running version renders in the bottom-right of every screen.

Internal

Nothing below changes what a user sees; it's here so the release record is complete.

Test suite retrofit and risk-based coverage

internal · #29 · PRs #33, #35

Constitution Principle VI was amended (v1.1.0) from "every acceptance criterion maps to at least
one test" to a risk-based rule, because the old one made the suite grow with spec verbosity rather
than with risk. The suite was then retrofitted against it: 361 tests / 6,347 lines → 337 tests /
5,538 lines with coverage of core and cli unchanged at 95%
— the same 49 uncovered
statements, module for module.

Parallel _cli.py / _tui.py / _parity.py files for one behaviour collapsed into parametrized
tests where the parity check is the test, and each layer (contract/integration/unit/
performance) got a documented job. core's freedom from adapter imports is now enforced by ruff
(TID251) instead of a test that walked the AST, so it fails in the editor. Full-suite wall time
dropped from 118s to 62s serially and to ~8.5s under pytest -n auto — used by a new
tests.yml workflow, which is also the first to run the tests on push and pull request at all
(previously they ran only at release time or on manual dispatch).

Dependency pinning with a 48-hour cooldown

internal · #28 · PR #55

For supply-chain predictability, dependencies are pinned to exact versions rather than >=, and a
48-hour cooldown via uv's exclude-newer keeps a freshly published version from being adopted
before it has been in the world for two days. The ongoing maintenance target is that each release
bumps to the newest stable version older than 48 hours. Dependabot also bumped
actions/checkout 4 → 7 (#15) and
astral-sh/setup-uv 6 → 7 (#14).

Versioning and release rehearsal

internal · part of PR #30

__version__ is no longer a hardcoded literal — it's stamped into src/choom/_version.py at
build time by hatch-vcs, falling back to 0.0.0 for a source checkout or editable install. The
build hook is disabled by default precisely so an editable install doesn't stamp a development
version; real builds opt in with HATCH_BUILD_HOOKS_ENABLE=1. A new release-dry-run.yml
(workflow_dispatch) rehearses a release end to end — quality gate, build with a proposed
version, install, assert choom --version matches — and has no PyPI credentials, so it cannot
publish.

REQUIREMENTS.md retirement

internal · #41 · PR #50

REQUIREMENTS.md bootstrapped the project before GitHub issues took over that job. Its still-live
UX and design conventions were reshaped into a living conventions doc and moved to
docs/REQUIREMENTS.md, with references from other docs cleaned up.


Known gaps at release

  • Manual terminal verification is outstanding across several features. tasks.md for specs
    005, 006, 007, and 008 each leave one task unchecked: confirming the new key bindings and
    ctrl+c cancellation on Windows Terminal, iTerm2, macOS Terminal, PuTTY, and inside tmux. These
    need a human at a real terminal on each platform and are a pre-release manual gate under the
    constitution's own TUI verification rule.
  • CHANGELOG.md says the Links pane toggles on l; the shipped binding is b (rebound
    during #27 review because l already meant pane movement and read as 1 in most terminal
    fonts). The changelog entry is stale — worth a one-word fix in a separate commit.
  • docs/screenshots/execute-task.png still shows the old name. The assistant transcript in it
    says "using the proper endpaper command" and uses [[wikilink]] syntax that predates document
    links. It needs a re-recording, not an edit.