Skip to content

Releases: ezapmar/brainless-public

brainless 0.9.0

Choose a tag to compare

@ezapmar ezapmar released this 08 Oct 11:39

Windows, Linux without systemd, a public site, and the batch brain on a monthly API credit.

  • The batch brain on an API credit. Claude Max and Team plans carry a monthly Claude
    Platform credit that pays for raw API calls, not for the interactive CLI. The anthropic
    provider of tools/llm.py now has what it takes to run the night on it: a cost ledger
    (.agents/state/llm_costs.jsonl, every call with its tokens and list price), a budget
    (api_budget_usd in brainless.toml; past the warn ratio the health check and the
    watchdog say so, past the stop ratio every API lane runs on its fallback until the reset
    day), a billing error class that hands an exhausted balance to the fallback, and
    python3 tools/llm.py --usage for the spend per lane. A key linked to an account rather
    than a workspace sends anthropic_workspace_id. Guide: docs/shed.md.
  • A system prompt for the raw API. The API carries none of the context the Claude Code
    CLI loads from the vault, so anthropic calls send _Agent-Context/LLM-SYSTEM.md (house
    rules, a few lines) plus the owner's language from the profile. Measured the same day:
    one empty claude -p call carries about 18k tokens of CLI context, which is why the
    credit goes through the API and not the CLI.
  • The CLI's own receipt. claude-cli calls run with --output-format json, so the
    ledger also records what the subscription absorbed, at the price the CLI reports, and the
    answer is read past any notice a tool manager prints first.
  • Shared git sync for the workers. git_sync.sh replaces the inline pull in the
    wrappers: it aborts a conflicting rebase, restores the autostash, alerts once per
    incident and exits non-zero while the tree is unsafe, so a job skips its run instead of
    committing conflict markers. A timer that fires in the seconds after wake waits for the
    network, and the worker pushes every hour.
  • One installer owns every unit. install.sh substitutes the vault path into each unit,
    sets BRAINLESS_VAULT, skips the owner-only units unless asked (owner-only.txt), and
    seven timers gained Persistent=true. A test parses every unit and fails on drift.
  • Engine hygiene. fsutil.atomic_write behind every live wiki page, one timestamped
    log line (logline.py), one frontmatter parser, one JSON reader, utf-8 named on every
    file open for the Windows port, ruff in CI, a generated script index in docs/scripts.md
    with a test that fails when it goes stale. Six bugs from a code scan fixed (a Buzz reply
    with media, the lite path importing fcntl, a crashed job's lease, the compile digest
    depending on the machine, Telegram redirects re-checked on every hop). Dead code and a
    June-old archive removed; the entity phase reads the corpus once per run.
  • The AI shed. The always-on worker as a home for standing agent panes:
    brainless-herdr.service runs a headless herdr server, attach from a laptop with
    herdr --remote or a saved machine, from a phone with any SSH client. docs/shed.md
    covers the billing split (what runs on the credit, what stays on the subscription), the
    three layers that keep the credit the only money spent, and the first week's checks.
  • A public site. docs/ now serves as a GitHub Pages site: a front page on the kilim
    brand with the loop, the six voices, the Medium and X writing and the install lines, and
    a what's new page with every release in plain words. tools/build_site.py writes
    docs/whats-new.html and the Atom feed docs/feed.xml from this changelog; run it after
    editing this file (--check fails CI when they are stale).
  • Night dialectic experiment closed. brainless-dialectic-night.timer is removed:
    after 11 nights the local 4B model never produced a usable night (22 of 132 persona
    replies passed, best night 6/12 against a bar of 8/12). The personas collapse into one
    voice. --run night and its service remain for manual runs. Result in
    docs/local-inference.md.
  • Windows install. irm .../install.ps1 | iex in PowerShell does what install.sh
    does: checks git and Python (it skips the Microsoft Store stub), clones, makes the
    venv, puts brainless on your PATH and runs brainless init. It works in Windows
    PowerShell 5.1, the one that ships with Windows.
  • One command line for every platform. The commands moved from the bash script into
    tools/cli.py. bin/brainless and the new bin/brainless.cmd only find the vault and
    its Python.
  • Keys in Credential Manager on Windows, through the system API, never on a command
    line.
  • A Task Scheduler task for the background runs: at logon and every 15 minutes, with
    catch-up after sleep, on battery too, and with no console window popping up.
  • Linux without systemd (WSL, containers, some distros) gets one crontab line.
    brainless doctor crashed there before.
  • No more fcntl on the lite path. The compile reached it through the concept review,
    so Windows failed at import. A small portable lock replaces it.
  • Outside folders link as a directory junction on Windows when a symlink needs admin
    rights. Ollama installs through winget when you say yes.
  • CI installs on Windows as well, and runs the scheduled task once.

brainless 0.8.6

Choose a tag to compare

@ezapmar ezapmar released this 04 Oct 17:13

Runs that did nothing now say so.

  • A failed model call fails the run. weekly_reconcile.py and evening_closeout.py
    returned 0 when the model gave nothing back, so the run log read "ok" over a drift
    report that was two weeks old. Both now exit 1, name the cause (timeout, auth, error)
    and report report=0 or closeout=0. An idle day is still a clean exit.
  • Scans are parked, not retried for good. A document with no text in it, or in a
    format the converter does not know, failed the same way every week and raised the same
    notification. smart_processor.py now parks it: one notice, then nothing until the file
    itself changes. The empty _raw.md a failed conversion left behind is removed, and
    records of files that are gone are pruned.
  • The briefing is pushed within the hour. With two machines, the laptop held the
    morning briefing until the evening backup while the worker's 21:00 close-out created
    the same file. Two new files on one path, and every pull failed. vault_backup.sh --only <path> commits and pushes named paths alone, with the same remote guard and
    retry, and cron_wrapper.sh uses it for today's briefing.
  • Scores no longer add up. The run log summed every number in a day, so two compiles
    at hit@5 88 read 176 and the next single run looked like a fall. Scores and levels keep
    the day's last value; tallies still add up.
  • An idea is written once. The compiler took whatever slug the model chose, night
    after night, and one idea ended up on four pages. The prompt now names the ideas
    already held, and a proposal is skipped when a page has its slug, answers to its title
    or alias, or was archived by a merge. Existing idea pages are no longer rewritten.
  • lint --fix-links follows titles and aliases. A link that names a page by its
    title, an alias or another spelling is repointed when one page alone answers to that
    name, and keeps its wording as the display text.
  • Fenced drafts survive the dialectic. The splitter read a heading inside a fenced
    proposal as a section break, cut the draft and lost its closing fence, so the rest of
    the filed page rendered as code.
  • The pile count skips machine ledgers. Inbox/CRM, the per-organisation log that
    crm_capture.py keeps, no longer counts as Inbox files waiting on anyone.

brainless 0.8.5

Choose a tag to compare

@ezapmar ezapmar released this 28 Sep 19:22

Docs, and one line of tidying.

  • Where the logo is set, written down. Design
    now says how the icon reaches the three places outside the repo: the GitHub social
    preview (by hand, no API), the Telegram bot (setMyProfilePhoto) and the Buzz agents
    (the installers). A manual Buzz profile write must repeat the name and about text, or
    they are wiped. The reference deployment points to it from the persona install step.
  • One deny rule less. The persona settings no longer deny MultiEdit, a tool Claude
    Code no longer has. Nothing else in the sandbox changes.

brainless 0.8.4

Choose a tag to compare

@ezapmar ezapmar released this 28 Sep 19:10

Two fixes to the new brand.

  • The social card keeps the whole name. The 0.8.3 card was cropped to 2:1 and lost
    the b of brainless. It is now the full banner, padded top and bottom with its own
    night-blue ground.
  • Buzz agents keep their avatar. The installers set the kilim icon together with the
    display name. A Buzz profile update replaces the whole profile, so a reinstall that
    set only the name would have wiped the picture. BUZZ_AVATAR_URL points it elsewhere.

brainless 0.8.3

Choose a tag to compare

@ezapmar ezapmar released this 28 Sep 18:25

A face. No behaviour changes.

  • A new mark: the kilim brain. Anatolian weaving motifs on the nodes of a network,
    notes as motifs, links as threads. The README and the wiki open with the banner.
  • One palette, written down. docs/design.md holds the design point
    of view: eleven colours with their roles, logo rules, terminal colour rules, and CSS
    variables for an interface that does not exist yet. tools/brand.py is the code copy.
  • Logo files for every place a logo goes: SVG and PNG mark in four sizes, WebP, a
    square icon on night blue for avatars, a favicon, the banner, and a 1280x640 social
    preview, all in docs/assets/.
  • The installer speaks in the same colours, and only on a real terminal. NO_COLOR,
    pipes and TERM=dumb get plain text as before.

brainless 0.8.2

Choose a tag to compare

@ezapmar ezapmar released this 28 Sep 18:22

Security. A full audit after the repo went out more widely; if you run an earlier version,
update.

  • A file name can no longer run commands on a Mac. Notifications put the name of a
    document that failed to convert straight into AppleScript, so a file named with a quote
    and do shell script ran a shell command on the next hourly job. The text now reaches
    osascript as an argument, never as script. Same fix in health check, worker reach and
    the compiler.
  • Automated Claude calls get exactly the tools they are granted. A deny list left Read,
    Glob and Grep open, so the research lane could read the vault and hand it to WebFetch if
    a page it read told it to. Every call now passes --tools with its grant (none by
    default, WebSearch and WebFetch for research, Read for photos) and --strict-mcp-config,
    so the MCP servers you use interactively (mail, chat, drives) never load in a timer.
  • The personas and writing agents read only your vault. Their settings named the
    author's home directory, so on anyone else's machine nothing was denied, and the persona
    installer did not template them. Read is now scoped to the vault, every dotfile in home
    is denied (keys, tokens, shell history), and the unit, env file and team rules are filled
    in for the installing user. The writing agents lost WebFetch: an injected page could
    otherwise carry vault text out in a URL. WebSearch stays.
  • The backup never pushes a vault to a public repo. It commits everything, and a clone
    of the engine (or a public fork) has the public repo as origin. It now pushes only when
    GitHub answers 404 to an anonymous request for the remote, and keeps the commit local
    otherwise.
  • The leak scan passes when clean. It no longer reads __pycache__, and its private
    word lists live next to the registry instead of in the shipped script.
  • Examples and fixtures use invented names and topics.

brainless 0.8.1

Choose a tag to compare

@ezapmar ezapmar released this 26 Sep 20:07

What the first full lite install found, from the published one-liner to an uninstall.

  • A second digest on the same day no longer replaces the first. A laptop can digest
    twice in a day; the later one is now appended to the day's file. Before, the earlier
    digest was lost while its notes were already archived.
  • Chatter in front of a digest is cut, and caught. A digest that opened with the model
    explaining it could not search the wiki was saved as it came. The page is now kept and
    the preamble dropped, and the guard knows the new phrasing. The stricter check also
    finds older damaged pages, which lint now lists.
  • Search returns your notes before the command prompts. "What did I decide about
    price" used to rank the /decide instructions first. .wiki/_commands/ is out of the
    search.
  • The nightly change brief works on a lite clone. It listed nothing, because it skipped
    every page git ignores. It now keeps them when the brief itself is untracked.
  • Generated wiki files stay out of git. The index pages, which name your documents, and
    the lint report were visible to git add . in a public clone.
  • Aliases in your language. An English vault got Turkish aliases; they now follow the
    vault's language, with English added for other languages.
  • init says which vault the command opens. When another vault is already the
    default, the closing screen says how to use the new one. The Lite guide says where the
    day's notes go after the digest.

brainless 0.8.0

Choose a tag to compare

@ezapmar ezapmar released this 26 Sep 19:25

The lite profile: brainless on one computer, with a folder of notes and any model. It is
now what the installer sets up. The multi-machine setup is install.sh --profile full.
Guide: docs/lite.md.

  • Concepts decided in the terminal. brainless concepts review shows each waiting
    proposal and takes yes, no or skip (evet, hayır, atla); brainless concepts decide
    does one from a script. The same effect as a Buzz reply.

  • A lite command set. The lite profile hides the commands that assume the full setup;
    brainless profile lists them and brainless profile enable <command> turns one on.

  • An install test on every push. A second workflow installs on macOS and Ubuntu against
    a stub model and runs doctor --probe, add and tick.

  • Docs. docs/lite.md; the README install section now describes brainless init.

  • brainless.toml. One settings file at the vault root (tools/config.py). It fills
    the existing BRAINLESS_* variables as defaults, so the environment still wins and a
    vault without the file behaves as before. brainless config show prints what it sets.
    Template: brainless.toml.example.

  • Keys in the OS keychain. brainless config secret set llm_api_key stores a key in the
    macOS Keychain, libsecret on Linux, or a mode 600 file elsewhere. A key written into
    brainless.toml is ignored with a warning.

  • Folders by role, not by name. tools/paths.py resolves inbox, library, thinking,
    daily, beliefs, decisions and ideas from [folders], so a vault can call its notes
    Notlar. Compile, digest, dialectic, calibrate, concepts and media import read the
    roles. Localised names for new vaults live in tools/locale/<lang>/folders.json.

  • Any model. New providers in tools/llm.py: anthropic (API key), ollama,
    openai, grok, gemini, openrouter (each with its own key, never another's),
    gemini-cli and codex-cli (your own sign-in, run from an empty folder, Codex in its
    read-only sandbox). One model setting, BRAINLESS_LLM_MODEL, per lane if needed.
    llm.py --models <provider> lists models. Ollama and loopback endpoints count as local,
    so the no-cloud-fallback rule covers them.

  • brainless init. The installer now asks instead of assuming. install.sh sets up
    Python and the command, then hands over to brainless init: your name and language,
    folders named in that language, other notes folders to read (linked, never changed),
    the model (Ollama, which it can install; an API key, kept in the OS keychain; or a CLI
    you are signed in to), one test call, optional semantic search, the background entry
    and the permissions it needs, and a first run if you want one. --yes with flags runs
    it unattended. Your folders go into .git/info/exclude, so notes never reach git.
    Python 3.11 is now the minimum. install.sh --profile full keeps the old setup.

  • brainless doctor. One line per check: folders, model, key, Ollama, scheduler, failed
    jobs, last compile. --probe sends one tiny prompt.

  • One machine, one queue. brainless tick runs what is due from a SQLite queue:
    convert hourly, digest and compile each evening, lint and prune weekly. A night the
    laptop slept through runs at the next wake; jobs that need the network or the model
    wait for them; failures back off and then show in brainless queue.
    brainless schedule install adds the single launchd, systemd or Task Scheduler entry
    that calls it, on the lite profile only. brainless add captures a note or a file.
    On the lite profile a document dropped in the inbox is converted there.

  • Concept proposals wait without Buzz. On a machine with no Buzz identity they stay
    pending instead of going to an outbox nobody delivers.

  • Summaries without write access. smart_processor.py no longer lets the model write
    files: the model returns text and the script writes it. Book summaries run on any
    provider; photo OCR still needs the claude CLI and leaves photos in the inbox otherwise.

  • The research lane says when it cannot search. Without the claude CLI a web lane is
    skipped with a note instead of failing.

  • The vault is where the engine is. With BRAINLESS_VAULT unset, tools use the
    checkout they run from instead of a fixed home path.

brainless 0.7.0

Choose a tag to compare

@ezapmar ezapmar released this 26 Sep 08:04

Take a bad source back out, one document per source, concepts decided in Buzz, and
frontmatter that Obsidian can read.

  • Retract a source. tools/retract_source.py traces a source that turned out wrong:
    its summaries (raw twin and book folder included), the concept pages that cite it, the
    pages that link to it. With --apply --reason "..." it goes into
    _Agent-Context/retracted.md and the compiler never compiles it again. A concept claim
    that stood on it alone is struck and kept in Superseded, marked retracted with the
    reason; a claim with other sources keeps them. The validator lets only the retracted
    links go, and a page it refuses stays as it was and is named for a hand edit.
  • One document, one source. A raw conversion beside its cleaned file, and a reading
    sheet beside a book summary, stop compiling as separate sources. Their old summaries go
    to .wiki/_archive/summaries/ with the reason in LOG.md, and links move to the copy
    that stays. Concepts read one summary per document.
  • Concepts are decided in Buzz. tools/concept_review.py posts each concept proposal
    to #dreaming; reply evet, hayır or atla. The Sunday proposal pass reads the whole
    catalogue and stops while five proposals wait.
  • Contradiction check. tools/contradiction_check.py reads each night's new summaries
    against their nearest pages and writes real conflicts to
    _Agent-Context/CONTRADICTIONS.md and the change brief. No page is edited.
  • Run log fix. The run log dropped any line with a digit in a key, so a night of
    failed calls could read as ok. Fixed, and a partial run now warns in health.
  • Quoted frontmatter. A colon followed by a space in a title or summary made the whole
    frontmatter block invalid YAML, and Obsidian dropped the page's properties. The tools
    never noticed because they read values by regex. tools/file_query.py and the idea
    writer now quote a value when it needs quotes (concepts.yaml_scalar), and every page
    the model writes passes through concepts.quote_frontmatter before it lands: summaries,
    projects, digests and concept pages. Lists, block scalars and quoted values stay as they
    are, and a second pass changes nothing. A # inside a summary, which YAML reads as a
    comment and cuts off, is quoted too.
  • Readers strip the quotes. concepts.fm_value and lint_wiki.parse_fm return the
    value without its quotes, so search, the index and the graph export see the same text as
    before.
  • Repair existing pages once, from the vault root:
    python3 -c "import sys;sys.path.insert(0,'tools');import concepts as C;from pathlib import Path;[p.write_text(n) for p in Path('.wiki').rglob('*.md') if (n:=C.quote_frontmatter(t:=p.read_text()))!=t]"
  • Test: tools/tests/test_file_query.py.

brainless 0.6.1

Choose a tag to compare

@ezapmar ezapmar released this 25 Sep 19:26

Health sees the worker's LLM login.

  • Worker LLM row. The LLM breadcrumb (.agents/state/llm_status) is per machine, and
    the worker does the heavy LLM work. tools/worker_reach.py now copies the worker's
    breadcrumb over ssh each hour, with the worker's own file time, into
    .agents/state/worker_llm_status.json. health_check shows it as a second LLM row, red
    on an authentication error, so an expired worker login no longer hides behind the main
    machine's green row. BRAINLESS_WORKER_VAULT sets the worker's vault path, relative to
    its home (default projects/brainless).