Skip to content

Releases: RubenAmaury/esbi-cli

v0.4.2

Choose a tag to compare

@github-actions github-actions released this 13 Oct 04:35
1dc55a7

The Documentation link on the PyPI page opens the docs site.

Fixed

v0.4.1

Choose a tag to compare

@github-actions github-actions released this 06 Oct 15:38
79352ea

Pages from servers that send an accented character in a header are read, a clip dropped in inbox/ no longer waits for the night, and the per-page limit that protects runs from hostile PDFs now sees inside forms.

Fixed

  • The limit on drawing operations per PDF page counts what is inside forms. A page over the limit gets no figures, so a hostile or broken PDF cannot keep a run busy; but the count only saw the page's top level, where a whole form is one object, so a page holding one huge form went past it. The count now includes what forms hold, and stops one past the limit.
  • The cron advice says what the hourly line does. Where there is no launchd, sb init and sb schedule said "hourly is fine, it runs once a day", which stopped being true when the hourly tick started draining the queue. They now say the first tick after [run].nightly_time runs the nightly batch and later ones drain what is queued, up to [run].max_batches_per_day.
  • A clip or PDF dropped in inbox/ is taken by the next hourly tick. The tick only counted sources already in the queue, and a file in inbox/ reaches the queue when a run scans it, so after the nightly run a new clip waited until the next night. Files the run can read now count; one it cannot (an image without an OCR model) does not. Mail is still fetched by the nightly run.
  • A page whose server sends a header with an accented character is read. Some CDNs add a header such as smg-ip-region: Bolívar; rebuilding the downloaded response re-encoded every header as ASCII and failed with UnicodeEncodeError, so the page failed three times and was parked. The headers are now passed on as the server sent them.

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 06 Oct 02:48
722eb21

A big queue no longer waits a day per batch: the hourly tick drains it, up to [run].max_batches_per_day. PDF slide decks are named after their file instead of the title left in their template, figures in PDFs printed several pages to a sheet are found, and links pasted as one argument are refused instead of queued as one broken link.

Changed

  • The hourly tick drains whatever is queued, up to [run].max_batches_per_day. It used to run the next batch only when the last one stopped at the source limit, so a batch that stopped on its token or dollar budget (common with long PDFs), or sources added after the queue had emptied, waited for the next nightly run: one batch a day. The daily batch cap (default 6) now bounds a day's work and spend. After a model outage or an interruption it still waits for the next nightly run.

Fixed

  • A config value of the wrong kind names the right kind. [bench] models = "ollama/x" said it "must be text" (the kind of each item) instead of "must be a list", and a prices that is not a table said "a number". The error now names the list or table the key expects.
  • Figures of a PDF printed several pages to a sheet are found. In a PDF with two or more pages on one sheet ("2 pages per sheet", a handout or a booklet), each page is placed as a form, and its pictures and drawings were looked for where they sat on the original page, not where the sheet puts them: they were missed, or cut to a strip, or the figures of every copy were taken for one. They are now found where they are on the sheet.
  • A PDF is no longer named after the template it was made from. A PDF's metadata Title was trusted as is, so slide decks built on one template all got its leftover title: 16 lectures of one course became "Machine Learning Landscape & Python Basics", "(2)", "(3)" and so on. The metadata Title is now used only when the first two pages show it; otherwise the note is named after the file, with _ read as a space, extra spaces dropped and a .pptx/.docx/.key left by an export (Slides.pptx.pdf) removed. Notes already in the wiki keep their names: rename them in Obsidian, which updates the links.
  • Several links passed as one argument are refused, not queued as one broken link. sb add "$LINKS" with links separated by newlines or spaces (a shell variable that did not split, a paste) queued a single glued-together address that could never be read. A link must now have a host and no whitespace; sb add lists it as not a source and queues nothing, as it does for any bad target. Pass each link as its own argument.

v0.3.1

Choose a tag to compare

@github-actions github-actions released this 05 Oct 16:48
edd78bc

Mail you labelled after it arrived is no longer missed, PDFs full of charts read like the old engine again, and a real Ubuntu test found and fixed the problems of running on Linux: the nightly cron line, git without an identity, long and case-only titles, and a start with no home folder.

Changed

  • Supported platforms: macOS only, for now. Linux and Windows (WSL included) are not supported. Ubuntu 22.04 and 24.04 were tried in containers and the problems found there are fixed (below), but no support is promised: the package no longer lists Linux as a supported system, and the README, the landing page and the documentation say so, and sb doctor shows a platform warning off macOS.

Added

  • [run].max_batches_per_day (a whole number of at least 1, default 6): the hourly tick (sb run --if-due) runs no more than this many scheduled batches a day, counted from the nightly time and including the nightly run itself. Before, a large backlog was drained one batch per hour all day with no limit. Runs that stopped for an outage or an interruption, and manual runs, do not count.

Fixed

  • A file or disk problem is one line, not a traceback. A read-only vault, a full disk or a missing permission made sb add, run, lint, ask and init print a Python traceback. Now they print error: Permission denied: /path (or, for the queue and index databases, the vault's state database cannot be used (...). Is the vault folder read-only, full or in use by another program?) and exit 1; with --json the error object has the new code os_error (additive: contract 1 stays).
  • sb starts where there is no home folder (a uid with no passwd entry and no $HOME: a container, a service). import esbi_cli raised RuntimeError: Could not determine home directory, so even sb version crashed; now commands that need a home say to give explicit paths.
  • sb run | head no longer parks a source. The closed pipe was recorded as a failed attempt of the source being read (BrokenPipeError), and three of those parked it. Now the run stops quietly and the source goes back in the queue with no attempt counted.
  • sb schedule status on a system without launchd exits 0 and prints the cron line: there is nothing to query, which is not a failure (install and uninstall still exit 1, they cannot do what was asked).
  • sb update no longer says "Updated." when nothing changed. uv tool upgrade on an exact pin, or a release the package index does not list yet, exits 0 having done nothing. Now it compares the installed version before and after: Updated to X.Y.Z. or Nothing changed: X.Y.Z is still installed ....
  • A new vault's .gitignore was never committed (git status showed ?? for ever, and the rules that keep .esbi/ out did not travel with a clone). sb init now makes a first commit of the new vault, and .gitignore is one of the files the worker versions.
  • Linux and WSL get Linux advice. sb doctor told a Linux user to run brew services start ollama and said "launchd is not available here" with no way out; it now says ollama serve (or systemctl start ollama) and points to the cron line. sb today (and any command that opens an obsidian:// link) used open, which Linux does not have, so it only printed the link; it now uses xdg-open there (on WSL, install wslu). With no keyring on the system (a server, a container, WSL), sb email set-password and sb email fetch said "No recommended backend was available. Install ... keyrings.alt" (plaintext storage); they now say there is no keyring, where email capture works, and that cron cannot reach a desktop keyring. sb export --help showed "(default: /site)" because <vault> was read as a tag; it now says "the site folder in the vault".
  • On Linux, sources titled Foo, foo and FOO became three pages. macOS and Windows see those as one file name, so the second source got foo (2); Linux kept all three and every [[Foo]] link was ambiguous (and a vault shared with a Mac or Windows machine could not hold them). The same goes for a title that differs only in Unicode form (é as one character or as e plus an accent). A source page name, and a file dropped in inbox/ or saved from mail, now counts as taken when only case or Unicode form differs; a re-read of the same address still updates its page.
  • A source with a long Japanese, Chinese, Korean or emoji title could not be saved on Linux. File names are limited to 255 bytes there (ext4, also WSL), not characters, and a page title was cut at 100 characters: 90 Japanese characters or 64 emoji gave "File name too long" and the source was parked as failed. A title is now also cut to 240 bytes (never inside a character).
  • The cron line for systems without launchd (Linux, WSL) never worked. It started with a bare sb, but cron's PATH is /usr/bin:/bin, so an sb installed in ~/.local/bin was "not found" every hour and the nightly job silently never ran. The line printed by sb init --nightly and sb schedule now names sb by absolute path, quotes paths with spaces and escapes %.
  • On a machine where git has no name or email (a fresh Linux user, a container), the vault got no history. Every commit failed with git's "Author identity unknown" and a long warning after each source. Now a commit uses esbi-cli <esbi-cli@localhost> when git has no identity of its own; a name and email you configured are kept. Found by running 0.3.0 in a fresh Ubuntu 22.04 and 24.04.
  • Mail you labelled yesterday but that arrived long ago was never taken. The mailbox search counted the day a mail was received, so anything older than 14 days stayed invisible however recently you tagged it. Now every unread mail in the label is taken, however old, and the highest UID taken is remembered (per mailbox generation) so a mail added to the label later is taken even if you had already read it. A mail the server refuses to mark as read is no longer silent: sb email fetch says how many.
  • The notice [llm.x] timeout is now timeout_seconds is printed once a day per config file (the time is kept in notices.json in the cache folder, next to the update check's file; an unwritable cache only means more notices), not on every command. sb doctor still prints it every time.
  • A clip added from outside the inbox (sb add clip.md, sb ingest clip.md) now keeps its original: the file is copied unchanged into raw/inbox/ (never overwriting: a taken name gets (2)), because the raw/<date>-<title>.md snapshot holds the text after the page chrome was stripped. Clips dropped in inbox/ already ended up there.
  • sb doctor no longer tells an installed copy to run uv tool install --editable <site-packages folder> when sb is not on the PATH: the fix: line now matches how esbi-cli was installed (brew upgrade, uv tool upgrade, pipx upgrade, pip install -U), and the editable hint is only for a source checkout.
  • The messages no longer assume macOS: sb init says "this machine" (not "this Mac") and the keychain errors, sb email set-password and sb doctor say "system keyring" on Linux; on Linux sb doctor says the nightly job needs launchd, which only macOS has, and points at the cron line.
  • A config whose [paths].vault does not exist now fails with error: vault not found: ... (--json: {"error", "code": "vault_not_found"}, a new code, additive) instead of creating the folder and a .esbi/ inside it. Every command that opens the vault goes through the same check; sb doctor, sb init and the commands that only edit the config (sb ocr ..., sb email set-password) still work without it.
  • PDFs full of charts and diagrams read like the old engine again. A paper whose figures are drawn in layers (one test paper had its labels printed 80 times) came out with more than twice the text it has, and with no headings at all, because more than 200 big lines switched heading detection off. Now: a short line that a document repeats 8 times or more is a chart label and is dropped (unless it is a symbol inside a line of prose, such as the V of where V is); short lines packed into a small region of a page are dropped; and the number of headings is capped by the size of the document (8 per page, at least 40) by keeping the numbered and biggest ones instead of keeping none.
  • Figures with several panels are no longer cut, and a table beside a figure is no longer part of it. A drawn figure whose panels stand more than 30 points apart lost all but the one next to its caption (the left panel of the Transformer paper's attention figure, the first panel of a three-panel agent-loop diagram, the top row of a six-panel one). Now the panels under one caption, up to 120 points apart, are one figure, for drawings and for pictures alike (a panel narrower than a figure counts together with its sibling); a table of numbers is no panel; a figure keeps out of the column of another caption beside it (a drawn table next to a figure was taken into it, and the table's text was lost from the note); and another figure's caption, short or long, ends a figure's search upwards, so two stacked figures stay two.
  • Words cut at a line end are healed better. The test for a hyphen at the end of a line (a word broken in two, or a compound such as feed-forward) counted the second half of every cut word as a word of the paper, so multi-plicative, de-composed, ma-ture and lever-aged kept their hyphen. Now the halves of a cut word are not words of the vocabulary; a joined word is also accepted if it is a known word with an ending (leverage gives leveraged, omit gives omitted, similar gives similarity); and a first half that is a word of at least four letters, or of, in, non, ..., still makes a compound (sequence-aligned, mixture-of-experts). On 15 test PDFs (some papers twice) 42 of 1,367 line-end decisions changed, and by hand count about 38 ...
Read more

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 05 Oct 14:55
d00694a

Reading very long sources in full, a check that sb ask answers say what the pages say, prompt-injection hardening, machine-readable --json output for editor plugins, optional OCR with a guided model choice, a ChatGPT-plan provider (codex-cli), consolidated concept summaries (off by default), hourly backlog draining, a USD cost cap, and no AGPL dependency any more (PDFs are read with PDFium).

Security

  • Prompt injection hardening, with a corpus and tests. A hostile source (a web page, a mail, a PDF, a clip, a transcript) can tell the model to write anything, and a small model often obeys, so the worker now checks what the model wrote instead of trusting the delimiters around the source. tests/fixtures/injection/ holds 15 inert hostile sources (instructions in the body, in fake system turns, in a fake </source>, in a clip's title, in an image alt text, in a mail subject, in a PDF line, in a transcript; exfiltration through an image or a link; links to missing or private pages; page names that escape their folder; fake contradictions; raw HTML; a mail that asks to be sent to the cloud) and tests/test_injection.py plays a model that obeys all of them. What it found and fixed: (1) the one-line summary of a note, a contradiction note and a PDF figure caption could still carry an image or HTML (the index page loaded the image when opened: the address could carry other pages' titles out); (2) a Markdown link or a bare address added by the model could carry the same data (clicked, not loaded); (3) [[links]] the model wrote to pages that do not exist, or, in a public note, to email pages; (4) a public source could link to, or put a contradiction callout on, an email page, and a mail could write its text into a public page through a contradiction callout, which a cloud model reads later; (5) a concept named Home, index, SCHEMA, log, lint or a date shadowed the real page in [[links]]; (6) a quote spanning lines could forge a section heading; (7) a clip's source: could carry line breaks or HTML into the note; (8) a source could close its own </source> block in the prompt, and a title could add lines to the system prompt of the long-source reader. Now all model text is plain prose (no HTML, no image syntax); an address survives only if the source itself contains it, a link only if it names an existing page that a public note may point at, a contradiction only lands on the same side of the email line, and the prompt builders make a source's look-alike tags and chat markers inert. A note says when it removed addresses. sb ask --save gets the same treatment, and its answer can no longer cite an email page when the model sends text out. Still not guaranteed: that a model resists an injection (it often does not: the worker only limits what the output can do), that an invented but plausible summary or contradiction is caught, and that the images and links a web page itself contains (kept as linked images, and in raw/) do not phone home when the note is opened.

Added

  • sb info --json has sends_text_out, a boolean per task saying whether the text of a source leaves this machine for that model (a model that cannot be built counts as yes), so the Obsidian plugin does not have to guess from the provider name. Additive: contract 1 stays.
  • A very long source is read in full. Before, a source of more than [run].max_chunks chunks (16 of 8,000 characters by default) was sampled: the first three chunks, the last two and a few evenly spaced ones, so a book or a 60,000-word document gave a note about a third of it. Now every chunk gets its notes and the notes of each group of five chunks are merged into a section note (level by level if needed) until at most max_chunks remain; the plan and the detailed summary are written from those, never from the raw text, so no prompt outgrows the model's context. The terms, quotes and relations of every chunk are carried over by code and still checked against the source. A source of at most max_chunks chunks is read exactly as before. sb run --json reports the new step as {"event":"step","name":"merging section","index":2,"total":8}, like the chunk step.
  • [run].max_calls_per_source (default 60, at least 12): a hard cap on the model calls for one source, retries included. Calls are kept back for merging what was read and for the plan, the summary and the connections; when the cap stops the reading early the note starts with a warning callout saying how many parts and what share of the text were not read and where the unread part starts, and the run prints the same as a warning. Raise it for books; a source of 40 chunks takes about 55 calls.
  • sb ask checks that the answer says what the pages say, not only that its citations are real. Every sentence with facts in it must find its numbers, its proper names and most of its key words (accents, case, plurals and endings ignored) in the pages the model was given or cited; no second model call. A sentence that fails gets a ⚠ after it and one footer line ("Not found in the cited pages: ..."), and an answer where most of the sentences fail is refused like an uncited one. A sentence that says the pages do not have the answer is not checked, and neither are pages written in another language than the answer. It is a vocabulary check: it catches an invented number, name or topic, not a wrong relation between words that are all in the pages. Measured on 197 sentences of real llama3.2 answers over a Spanish wiki of 15 notes: it flagged all 51 hand-labelled unsupported sentences and wrongly flagged none of the 119 supported sentences in answers that cite a page (5 of 146 over all answers, all of them in answers with no valid citation, which were refused anyway). sb ask --json gains an unsupported list ([{"sentence": ..., "missing": [...]}]; contract 1 is unchanged). [run].check_answers = false switches it off.
  • A backlog drains hour by hour. When a scheduled run stopped only because it hit [run].max_sources_per_run and sources are still queued, the next hourly tick (sb run --if-due) runs the next batch instead of waiting for the next night. One batch per tick; never after an outage, an interruption or a budget stop, and never while another run is active.
  • Unticking undoes a tick. Unticking a read source's box in the daily note of the day it was processed puts it back to processed (the read date is cleared) the next time sb index or sb run registers ticks. A source with no box there, or ticked anywhere in that note, is left as it is. Daily notes are regenerated from state, so a read source always shows ticked and an unticked box is always your doing.
  • A model-server outage is visible. When the latest run stopped because the model could not be reached, the daily index says so first in "To review" (with how many sources are waiting), and sb doctor shows a WARN last run line with the fix (start Ollama or check the model, then sb run). A later run that reached the model clears both.
  • [run].max_usd_per_run (a number, unset by default = no cap) stops a run once its estimated cost reaches that many USD, like max_tokens_per_run does for tokens: the rest stays queued, with no attempt counted, and the run is recorded as usd_budget (also the stopped_by of sb run --json's finished event, a new value of an existing field). The estimate is the tokens a model used times its price in [bench.prices] (USD per million tokens, the table sb bench uses). Only models that send text out count: local models are 0, and so are claude-cli/ and codex-cli/, which are flat-rate subscriptions. A model without a price counts as 0.
  • The smoke test that every wheel passes before a release (scripts/smoke.sh) now reads a real PDF with the installed package, and a test fails if an AGPL package becomes a dependency again.
  • --json on sb version, status, info, doctor, add, ask and run, for editor plugins and scripts (contract version 1, reported by sb version --json as contract). Each command prints one JSON object on stdout; sb run --json prints JSON Lines (started, source_started, step, source_done, source_failed, finished), flushed line by line, with the human progress lines dropped. A failure prints {"contract":1,"error":...,"code":...} and exits 1, with no traceback; exit codes are the same as without --json.
  • Reading images is a choice you can make, see and change. sb ocr status shows whether it is on, the model, whether Ollama has it, its download size, this machine's memory and whether Ollama is new enough; sb ocr enable [--model NAME] [--pull] turns it on (and downloads the model only with --pull or a typed yes); sb ocr disable turns it off and keeps the model choice. [llm.ocr] enabled = false does the same from the config.
  • sb init asks "Read images and scanned PDFs (jpg, png, ...)?" and, on yes, shows the vision models with their size and the one recommended for this machine's memory, lets you type another Ollama model, says whether it is installed and asks "Download it now?" (progress is shown; an interrupted download resumes). Flags for scripts: --ocr/--no-ocr, --ocr-model NAME, --pull-ocr-model. Nothing is downloaded without that flag or a yes.
  • DeepSeek-OCR (deepseek-ocr:3b, 6.7 GB) is a known model for machines with 16 GB of memory or more (never the default: qwen3-vl:2b-instruct is the recommended one), asked with the instruction it needs (not measured above 8 GB: on an 8 GB Mac it loads at about 10 GB and takes minutes per image); any other Ollama vision model gets a general one. sb doctor warns when this machine has less memory than a known model needs, or Ollama is older than it requires, and fails with the exact ollama pull command when the model is missing.
  • codex-cli/<model>: use your ChatGPT plan through OpenAI's official codex tool (codex login once), the twin of ...
Read more

v0.2.1

Choose a tag to compare

@github-actions github-actions released this 05 Oct 02:37
1fef723

0.2.0 has a bug in its update check: do not use it, update to 0.2.1 (brew upgrade rubenamaury/esbi-cli/esbi-cli, or uv tool upgrade esbi-cli; sb update itself crashes in 0.2.0).

Security

  • Fetching a link (and the update check) no longer follows HTTP_PROXY, HTTPS_PROXY, ALL_PROXY or NO_PROXY from the environment. Behind a proxy the proxy resolves and connects, so the check that a link points at a public address no longer described where the request went, and a proxy inside the network could be made to reach internal hosts. If your network only has a proxy, set [network] use_environment_proxy = true; sb doctor then warns that the address checks are done by the proxy.

Fixed

  • The update notice now follows the config the command was run with: sb status --config other.toml honours [update] check = false in other.toml, not in the default config.
  • sb update now says to run sb schedule install when a nightly job is installed, so the job is rewritten by the new version (it never touches launchd itself). sb doctor also warns when the job points at another uv tool or pipx environment than the one that is running.
  • sb bench --help named its config section "bench section"; it now reads [bench].
  • Pressing Ctrl-C (or sending SIGTERM) during sb run left the source being read stuck as in progress, and the next run counted that as a failed attempt, so three interruptions parked a perfectly good source. Now the source goes back to the queue with no attempt counted, the run exits with 130 (Ctrl-C) or 143 (SIGTERM) and says Interrupted: 1 item put back in the queue.. A note is never cut in half: a signal that arrives while a note is being written waits until it is whole. sb ingest and sb reingest stop the same way (sb reingest no longer risks losing a note's read state if stopped at the wrong moment). An interrupted scheduled run does not count as tonight's nightly run.
  • A chunk of a long source that the model could not read (invalid twice) used to be skipped; it is now read again in two halves first, and the warning names the chunk only when both halves fail too (or says only half was read).
  • English leaking into a note written in another language: the check covered the abstract only. Now the executive summary, key points, concept descriptions, key ideas, open questions and each paragraph of the abstract are judged on their own, the retry names the offending fields and the warning lists them. A language without a stopword list is still skipped.
  • Glossary trivia: duplicate terms (case, accents, punctuation, and acronyms in either letter order such as IA and AI), generic words ("data", "system") and definitions that say they have none ("not defined in the text") are dropped. Terms still have to appear in the source.
  • Invented diagram edges: a relation whose end is neither in the source nor a concept, entity, term or alias of the note (translated or inflected is fine) is dropped; the run reports how many. The prompts now ask for relation ends as names (1-4 words), not sentences: on five real notes 32% of the ends were longer than six words (often a sentence cut at 40 characters) and now 6% are. Small models still rarely tie an end to a concept of the note, so the concept map is often left out when fewer than two relations survive.
  • The detailed summary of a long source failed on its first try about one time in four with a small local model (llama3.2): the abstract, one string with no bound, never closed (paragraphs repeated until the token cap) and, once closed, the whole answer did not fit the cap. The digest now asks for the abstract as a list of 3-4 paragraphs and for 4-6 short key ideas, which bounds what the model's grammar can enforce; first-try failures on the same prompts went from 6 of 32 to 1 of 25. The retry with a shorter hint stays.
  • Glossary terms come out of PDFs and Markdown clean (no *, _ or spaces around them) and a one-letter term (a formula symbol) is dropped. The hint for key ideas no longer says "why it matters", which a small model copied into Spanish notes as "Matters porque".
  • sb version --check, sb update and sb doctor crashed with a traceback, and any command run in a terminal printed one after its own output, because the update check called the download helper with an argument name that had been renamed. The check can no longer break a command, whatever goes wrong inside it.

Changed

  • Digest (the model's answer for the detailed summary) has paragraphs (a list) instead of abstract (a string); Digest.abstract is still available as the joined text. Adding a language to lang.py now also takes generic_terms and disclaimers (see the how-to "Add a language").

Added

  • Image attachments in mail. PNG, JPEG, WEBP and TIFF attachments are saved to inbox/ next to the mail's note, so they follow the same road as any image you drop there: read with the local [llm.ocr] model when it is configured, listed by sb scan as not read (with the hint to enable OCR) when it is not. The bytes decide what a file is, not the declared type or the name; images under 200 px or a few KB (signatures, logos, tracking pixels), over 5 MB, or beyond 15 MB per mail are skipped. Like mail PDFs, they count as email for the privacy rules.
  • [email].follow_links (off by default) and follow_links_max (3 per mail, 1 to 10): the http(s) links in a mail's text, minus tracking redirects, unsubscribe/preferences/view-in-browser links and pictures, are queued, never fetched while the mail is captured. The nightly run reads them as email: only by [llm.private], the resulting note has kind: email and is hidden from cloud models like any email note. sb email fetch reports N images saved and N links queued.
  • sb email configure no longer drops follow_links and follow_links_max when it rewrites the [email] section.
  • A smoke test that installs the built wheel in a clean environment and runs the first commands a user runs (including one at a terminal, where the update notice runs). It runs in CI on every pull request and before every release, so a package that crashes cannot be released: the unit tests, which fake the network and the install, had all passed on 0.2.0.

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 04 Oct 19:32
33fcff7

Superseded by 0.2.1. The update check in 0.2.0 crashes (sb update, sb version --check, sb doctor). Do not install 0.2.0.

Updates you can see and run, a safer nightly job after a Homebrew upgrade, names that carry their unit, and a repository with code scanning, dependency review and protected branches.

Added

  • Updates you can see and run. sb update shows the command for the way esbi-cli was installed (Homebrew, uv tool, pipx, pip), asks Run it now? [y/N], and runs it (--yes skips the question, --dry-run only prints it). A source checkout, an unknown install, or a uv tool pinned to a git tag or a wheel gets the steps to follow by hand. sb version --check prints the installed and the latest version.
  • An update notice. Once a day esbi-cli asks the GitHub releases API for the latest version (one anonymous HTTPS request: no vault data, no identifier), and a command run in a terminal ends with one line on stderr when a newer one exists. It never appears after the nightly run, schedule, update, setup, init, version or doctor, in a pipe, or after a failed command. sb doctor has a version line. Turn it off with [update] check = false or ESBI_NO_UPDATE_CHECK=1. Nothing is installed by itself.
  • A how-to page, "Update esbi-cli", with what each install method runs, what the check sends and how to turn it off.

Changed

  • The documentation sources are no longer in the repository. The site (https://rubenamaury.github.io/esbi-cli/docs/) is built on the maintainer's machine and only the built site is uploaded, to the gh-pages branch that GitHub Pages serves. README and CONTRIBUTING link to the site; report a wrong or missing page as an issue.
  • [llm.*].timeout is now timeout_seconds, so the unit is in the name. The old timeout still works and prints notice: [llm.<task>] timeout is now timeout_seconds once per run; if both are set, timeout_seconds wins. sb init writes the new name.

Fixed

  • The nightly job survives a Homebrew upgrade. sb schedule install wrote the versioned Cellar folder (.../Cellar/esbi-cli/0.1.0/libexec) into the launchd job, and brew upgrade deletes that folder. It now writes the stable .../opt/esbi-cli/libexec path that Homebrew keeps pointing at the current version. sb doctor warns about a job installed the old way; run sb schedule install once to fix it.

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 04 Oct 05:31

The first public release.

Added

  • Capture: PDFs, web links, Markdown clips (Obsidian Web Clipper), YouTube transcripts with timestamp links, email over IMAP (read-only, PDF attachments included), and, optionally, images and scanned PDFs read by a local vision model (OCR). A queue with retries, an inbox folder, sb add, sb scan and sb run.
  • Rich notes: for each source, an executive summary, a detailed summary, key ideas, a glossary, verbatim quotes checked against the source, a concept diagram drawn by code, figures from PDFs, and connections to the notes you already have. Long sources are read in chunks. sb reingest rebuilds old notes from the saved originals.
  • The wiki: sources, concepts, entities and syntheses as plain Markdown, an index, a log, a daily index note with read tracking by ticked checkboxes, lint, a review queue, and sb export for a read-only website.
  • Ask your wiki: sb ask answers with citations to your notes; search by keywords, optionally fused with local embeddings ([llm.embed]); sb eval measures retrieval on your own questions.
  • Models: local (Ollama, LM Studio), your Claude subscription through the official claude tool, or an API key (Anthropic, OpenAI-compatible), with a per-task choice, a fallback model, and token budgets. sb bench compares models on your own data.
  • Language: the language of the notes is a setting (en and es; adding one is a data-only change). The CLI and the documentation are English.
  • Privacy: email is read only by a model on your machine and is never shown to a model that sends text away. The mail password lives in the macOS Keychain. Fetching refuses non-public addresses and pins the connection to the address it checked.
  • Setup: sb init creates the vault and the config and asks only about what is optional (Obsidian, model choice, nightly job, git backup, Gmail, Web Clipper); sb doctor checks the whole setup; a nightly launchd job on macOS (a cron line elsewhere).
  • Versioning of the vault: with git installed, the vault is a repository and every ingested source is a commit; without git everything else works.
  • Documentation (tutorial, how-to guides, a complete command and configuration reference, concepts, FAQ), a landing page, and a Homebrew tap.