Skip to content

v2.4.0

Choose a tag to compare

@pgalko pgalko released this 17 Oct 06:33
· 89 commits to main since this release

BambooAI 2.4.0 — the words beside the numbers

Training data comes with writing: what the athlete wrote under a ride, what the coach replied, the plan's prose, a note on a day. 2.4.0 puts those words beside the numbers as data the analyst can read, cite and count; keeps what Intervals.icu has already sent so a load fetches only what is new; adds the rider's own settings — thresholds, zones, custom fields — as a file the data is read against; and gives every report a title, so a PDF can be handed to someone who has never seen the app.

The words beside the numbers

  • Context. The Context option of an Intervals.icu load (on by default) turns the words into a table of passages — one row each, with its day, its kind, its author's role and the text as written — and a table of codes: the new Coder seat reads every passage once against a codebook (fatigue, recovery, instruction, deviation, …), labels it, and renders a passage not in English into English, kept beside the original. Coded passages are remembered per subject, so a window seen before is coded in seconds. A third file, the planned workouts, carries the prescription: each planned session, the activity it was done as, its compliance, the plan's duration, load and targets, the step lines and the structure.
  • In the analysis. The Analyst sees a map of the words — the span, the passages by kind and month, the authors, the languages, the codes with their counts — never the text. In the kernel the words are CTX: CTX.frame() and CTX.codes() are the two tables; CTX.grep, CTX.around, CTX.between and CTX.on find passages; CTX.text reads one whole; READ CTX puts a question to the Reader over them. The report cites a passage as [C.417], quoted verbatim and marked rendered when it was translated; a count of codes is reported as the model's reading, not as what was said. The plain-language version keeps the quotes and their citations. The Reviewer reads the words through a lens of its own.
  • The codebook is yours. When no code fits, the Coder proposes one, uses it meanwhile with its rows marked, and leaves the decision to you: the Context card of the load dialog says how many proposals wait and opens the codebook screen — each proposal with the passages it came from (confirm it, confirm it under another name, merge it into a code the book has, or decline it), the codes by group with their definition, status and the last load's uses, export and import as JSON. A confirmed change applies from the next load; nothing already coded is re-coded.
  • Routines carry context. A routine saved over the words runs on a new window with that window's words and codes.

The Intervals.icu store

  • Every activity the executor has parsed is kept in a store under the key's folder, with the chats fetched for it. A load is a view over the store: the window's activity list is fetched, the activities the store lacks (or whose file changed) are downloaded, the rest are assembled from disk, and the chats of activities older than sixty days are reused. The load dialog says what came from the store and what was downloaded; Everything again fetches the whole window. Activities fall out of the store after 400 days unless a load used them in the last thirty. The Dataset cache panel shows each key's store — its activities, chats, span and size.
  • The store and the loaded files live in the Docker volume bambooai-datasets, which outlives the container and its image: an upgrade keeps them. BAMBOO_EXECUTOR_DATASETS in .env names a folder on the host instead.

The rider profile

  • The Rider profile option of an Intervals.icu load (on by default) writes the account's settings as a file beside the data: weight, height, resting HR and age; per sport, the FTP, the thresholds and the zones with their bounds, and the power-duration model's estimates; every custom zone set the account defines, zone by zone, with the day it was last defined; and the meaning of every custom field — its code, type, units and options — so the columns of the other files explain themselves. When the account defines custom zone sets, a second file carries the time in each custom zone per ride, with the bounds in force that day, and the analyst is told the custom sets are the ones meant when reading intensity. The intervals, wellness and summary files carry every custom field under its code — a select as its option's text, with the number beside it. Everything comes from the account's own record, nothing is named in code, and nothing identifying goes in. The summary file carries the settings in force on each day.
  • A load can bring up to twelve auxiliary files now (eight from a loader, four attached by hand), and the data description keeps to a budget however many there are.

Reports

  • The title. The report's first line is its title — the Analyst's statement of what was found, written for a reader outside the thread. It heads the Answer tab, both versions, and the PDF export, whose top section puts it above the question as the Analyst understood it (so a follow-up reads whole without the thread), the data the report stands on (the source, the window, the files) and the day, mode and reproduction verdict. The body is whichever version is on screen, its figures drawn on a print layout and its citations marked; the browser offers the title as the file's name.
  • Routines. A failed script returns what it printed, so a run that stops is diagnosed from its own output; a cut run's words are the window's; the run's check row counts rows, not lines; an input is never a choice over a column the script computes; Save as routine returns at once and run zero verifies in the background (the card reads verifying…, then the verdict); the run dialog says how long the last run took before you pay for the next; a run's folder mirrors the recorded layout.
  • The contract. A count the data determines is computed; a figure's numbers are never typed. An earlier cell's output within a hair of the cap rides whole.

The web app

  • The three load dialogs (Intervals.icu, Endura, SweatStack) follow one grammar: what you load first, then what else comes with it as equal cards, then how — Only what's new or Everything again.
  • Dates are the person's: today is the local calendar day in every dialog, and a date being typed no longer snaps the other one.
  • The dataset chips are one row that scrolls.

Configuration

  • A new seat, Coder (reasoning off), in every tier of LLM_CONFIG_template.json; a configuration without one uses the Reader's seat. The Reader and the Coder run on DeepSeek flash in every tier.
  • The default preset is cost: an OpenRouter key alone runs it; performance and max need an Anthropic key as well.
  • The benchmark file gains the context rows and a context_enabled heading.
  • The README is rewritten in plain prose.

Hosted edition

  • The executor's datasets live in a Docker volume per user (nomad/jobs/; the Nomad docker plugin needs volumes { enabled = true }), so a user's store outlives a dispatch. Executor image v60.

Upgrading

pip install -U bambooai
bambooai serve

The first start builds the new executor image (bambooai-executor:2.4.0-v60; a few minutes). The store starts empty: the first Intervals.icu load downloads the window whole, the loads after it only what is new. Favourites, labels, memory and routines are unchanged; a routine made before 2.4.0 runs as before. If you keep your own copy of the configuration template, the shipped one has the Coder seat to copy; an existing .env keeps the level it names.

Full changelog: v2.3.0...v2.4.0