ci / check (push) Canceled after 0s
An image counted as half a million tokens: the context estimate measured its base64 as text, so a 1-3 MB screenshot read as "context at 150-280%" the moment view_image added it, and the session compacted after every image. An image now counts by its dimensions (28 px patches, at most 16k tokens, a flat 1600 when unreadable) everywhere the CLI estimates -- the meter, pruning, /context and the no-usage fallback of all five dialects. Images over 1600 px or 500 KB are shrunk to 1600 px when ImageMagick is there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
17 KiB
17 KiB
Changelog
All notable changes to LLeMbas CLI. The format follows Keep a Changelog, and the project uses Semantic Versioning.
[Unreleased]
[1.5.1] — 2026-10-23
A screenshot no longer makes the session compact.
Fixed
- An image counted as half a million tokens. The context estimate measured an image's base64
as text, so a 1–3 MB screenshot read as "context at 150–280%" the moment
view_image(or an@attachment) added it, and the session was compacted -- after every image, since the summary drops pictures and the model looked again. The provider's own count, a few thousand tokens, was never in question. An image now counts by its dimensions (28-pixel patches, at most 16k tokens; a flat 1600 when the size cannot be read), everywhere the CLI estimates: the context meter, pruning,/context, and the estimate a provider that reports no usage falls back to. - Screenshots are sent at 1600 px. Any image over 1600 px or 500 KB is shrunk to 1600 px on its longer edge when ImageMagick is there (only files over 3.5 MB were before): no more detail than the model is billed for, and a lighter request.
[1.5.0] — 2026-10-20
Harness spec 2.0.0: background work is one thing — a job — for commands and subagents alike, and the person sees it.
Added
- Subagents in the background.
tasktakesbackground: true: the call returns at once with a job id and the model carries on; the subagent's report arrives as a message in the conversation when it ends — at the next step while the model works, as a turn of its own otherwise. A running subagent can be messaged (job_send: given to it at its next step) and a finished one started again with its context intact; a subagent can message the main agent before its final reply (report: a finding to act on now, or a question). Approval cards from a subagent say which one asks. - A subagent has a session of its own, kept with the parent: its transcript survives a
resume and can be read later;
/sessionsandsession_searchleave children out. job_list,job_output,job_stop,job_sendreplacebash_list,bash_outputandbash_kill(which still work as former names, and a rule written for them still applies): one list of the session's background commands and subagents, one way to read, stop and message.- Jobs belong to the session that started them, not to the process: another session's jobs are invisible, ids run per session, and a job's end note goes to its own session — kept for it when it is not open, delivered when it is resumed. Jobs are stored: a resumed session lists what finished while it was away, and a job the process died under is shown as lost with the output it had.
- Jobs in the terminal. The status bar counts the session's running jobs (
2 jobs, with!when one ended unseen or has output the model has not read)./jobslists them — kind, id, description or command, state, duration — and from thereEnteropens one andkstops it: a command opens as its live output; a subagent is entered, its transcript shown in the conversation's place with a header saying where it is, and anything typed goes to it (a finished one starts again with the message, context intact).Escleaves./jobs <id>and/jobs stop <id>do the same from the prompt. A background call's line shows its job under it (→ job7 (explore: description) running…), and an approval card from a subagent names it. - Ctrl+B moves the command the model is running in the foreground to the background now; the call returns with what it had printed and the job id.
- Quitting (
/quit, Ctrl+C twice, Ctrl+D on an empty box) or/reloadwith jobs running asks first:N jobs running — stop them and quit? - Over the link (capability
jobs, harness spec 2.0.0): a LLeMbas server lists a session's jobs, reads a job's output, stops one, messages a subagent and reads its transcript (_lembas/jobs,_lembas/job/output|stop|send|transcript);jobandjob_noteevents, the jobs in_lembas/session/status, the subagent on an approval request, and a job's note as amachineprompt. A session a terminal holds answers the same through the hub. limits.jobs(background commands a session may run at once, default 8) andlimits.subagent_steps(a subagent's step backstop, default 50) in the configuration.lembas -pwaits for the jobs the prompt started and gives the model their notes before it exits (--no-waitskips that);/agentslists and describes agents over the link too.
Changed
- A command's
timeoutis when it stops blocking, not when it dies. A foregroundbashstill running at its timeout (defaultlimits.bash_timeout, 2 minutes) goes on in the background as a job, and the call returns what it had printed with the job id;Escstill kills it, so doesjob_stop.background: truereturns at once instead of after 300 ms. - A finished job wakes the model in every front end — the terminal,
lembas -pand a session the web UI holds — where it used to reach only the terminal, and there as an unmarked message to whatever session was open. Every such message now carries its mark, and the terminal shows it as the harness's turn, not the person's. - A stopped command reads "stopped (SIGTERM)" rather than "exited with null".
- The subagent's preamble and the built-in
exploreandgeneralinstructions are prompt texts of the harness spec (blocks/subagent.md,agents/*.md), shared with the server; a subagent is no longer told aboutplan_writeandask_user, which it does not have, nor aboutskill_viewwhen it lacks it.exploregets the job tools; every subagent getsreport. - The capacity rule also counts the subagents already running.
Fixed
- A subagent in a worktree that was stopped or failed kept its branch silently; the branch is
named in its report now. In a worktree, the edit-mode guard and the plan directory pointed at
the main checkout's
.agent. - A subagent's error or notice was dropped: its report said
ended: errorwith no message. /reloadwith background jobs running lost them as orphans; so did quitting with one that ignored SIGTERM (the kill timer never fired at exit). A command whose child kept stdout open stayed "running" after it had exited.- An agent file with broken YAML frontmatter was silently taken as having none; it is reported at start.
- A
!commandin the terminal could not be stopped. - Headless runs opened a second line-reader for a parallel subagent's approval.
- Ctrl+D on an empty prompt quit only in a comment; it does now.
bun testran with a 5-second timeout per test, whateverbunfig.tomlsaid: Bun 1.4 does not read[test] timeout. The test script andscripts/ci.shpass--timeoutexplicitly.
[1.4.0] — 2026-10-20
Harness spec 1.2.0: the library's tools are the same tools in LLeMbas.
Changed
- The harness spec's memory, notes and skills tools now fit both projects. The CLI's facts in
their descriptions — memory files and targets, project notes, supporting files, project skills,
session_search— are the spec'svariables, filled with the CLI's own values, so what a model is sent here is word for word what it was; LLeMbas sends the same tools with its own facts (LLeMbas 1.5.0). A CLI linked to an instance (library: lembas) therefore seesmemory,note_view,note_manage,skills_list,skill_viewandskill_managewhether the library is its own or the instance's, where it used to see the instance'smemory_add,notes_createand the rest. - Note and knowledge-document ids are strings in the tools' parameters, as they are on an instance; the number is still accepted.
- Tool descriptions are filled by the prompt texts' rules, and the descriptions inside a tool's parameters are filled too.
Added
narrowin the harness spec: what a project offers of a shared tool's parameters where it offers less than all. Three conformance areas, run by both projects:fill,narrow, andmemory— one change or a batch, applied together, against the size limit, messages included.
[1.3.0] — 2026-10-18
Harness spec 1.1.0: planning as one structure shared with LLeMbas.
Added
plan_writeandplan_update, offered in every mode: the model writes its plan as a structure — title, summary, findings, objectives, phases of tasks — and keeps it current as it works (a task doing, done, or dropped with why; work added; a finding recorded). Ids (p1,t3,o2…) are given by the CLI, never by the model, and an unknown id is an error naming the known ones. The plan is the session's: it is stored with it, comes back on resume, and is gone on/new. The panel above the prompt shows the active phase, the task being done, what is next, the last two done and the count while anything is open;/plan showprints the whole plan with its ids,/plan cleardrops it, and/planssays whether this session has one.- A
planblock kind: a plan change is not drawn as a tool line in the transcript; the panel and the card follow the plan itself. - Over the link, an instance now hands the device what only it knows about a chat
(
_meta.lembasofsession/newandsession/prompt, capabilitiescontext,library,prototypes): the chat's own instructions reach the prompt under## Instructions from <instance>, the account's personalization is used for that session in place of the device's, the knowledge bases the chat may search are named to the model, and whether it may write a prototype. A later prompt's context replaces the earlier one. - The plan travels as a structure (capability
plan_state): theplansession update carries it as_meta.lembas.planbeside ACP's flat entries (null when cleared),_lembas/plancarries it with the card,_lembas/session/statusanswers it, and a session opened from the store says its plan at once. _lembas/session/rewind(capabilityrewind): the web UI editing or regenerating from a turn takes that turn and every later one out of the conversation and the history — as/undodoes, through the same store marking — without touching the files; a session a terminal runs is rewound there, and its transcript redrawn. A rewound turn's id is forgotten, so the web UI re-sending it runs the turn anew rather than being answered what the reverted turn said.- Prototypes in the terminal: a completed
prototype-chat/prototype-pagefence in a reply is saved as a file — the model's output as it is, under~/.local/state/lembas/prototypes/<session>/<n>-<slug>.html, never in the project — and drawn as one line saying where;/prototypelists this session's,/prototype <n>prints one's path. The prompt offers them only when the instance says so for the chat, or withprototypes: truein the global config for a terminal session. - The library's scope: every call to the instance's library made for a session the instance
gave a library context carries
_meta.lembas.scope(the session id), so the instance answers within that chat's bases and data group;knowledge_search'sbaseis read against the bases in scope as LLeMbas reads it — by id, then by name whatever its case, an unknown one answered with the bases there are (resolveBase). - Conformance areas
plan(normalise, update, todos),toolcall_index,prototypeandlibrary_scope; an area the spec has and this implementation does not answer yet is skipped by name rather than failed.
Changed
plan_submitpresents the plan written withplan_write, not a file: the card shows the plan with its ids, and a copy still goes under.agent/plans/<date>-<slug>.mdfor the record. Itspathargument is kept for callers that send it and ignored. With no plan written it says to callplan_writefirst.- The system prompt is the spec's one shared text (
system/default.md), with the CLI's facts filled into its variables — the opening line, the terminal as the surface, the file tools, the background-command and git sections, and the current plan with its ids on every step while one exists; the sharedblocks/library.mdandblocks/prototypes.mdjoin it when their tools are offered. A bullet whose variable is empty is left out, and a variable left unfilled is an error rather than text sent to a model. - The loop's numbers come from the spec's
loop.json(the step backstop, how many calls run together, how often an empty reply is asked again), and so does the wrap-up message, which now names the limit reached: "The time budget for this prompt has been reached…". - The default theme is
moria, the LLeMbas web UI's own;lembasandlembas-lightremain selectable. The working line is a plain braille spinner with the verb, without the faces, and the welcome box no longer carries the ☤ glyph. - A tool-call fragment streamed without an index continues the call started last, not call 0, so a server that numbers only the first fragment of each call no longer merges two calls.
- A permission rule written for
todoapplies toplan(the keyplan_writeandplan_updateare checked under), asquestionapplies toask_user.
Removed
- The
todotool.todois now a former name ofplan_write: a call under it — from a stored session, an agent file, or a model trained on it — becomes one phase called "Work" with its items translated (pending → todo, in_progress → doing, completed → done, cancelled → dropped). - The
☤glyph and the face frames of the spinner, from the TUI.
[1.2.0] — 2026-10-14
Added
lembas remote list | add <dir>… | remove <dir>… | enable | disable | mode <m> | terminal <on|off>manages theremote:block without editing YAML, keeping the file's comments.addstores each directory as an absolute real path, skips one already covered by a root, refuses a missing one (nothing is written), and turns remote work on.--jsonprints one object,{"enabled", "roots", "max_mode", "terminal"}, with the defaults applied — for a program such as LLeMbas Desktop.lembas -l/lembas --local: local mode. Config, sessions, memory, skills, the library, snapshots, worktrees, caches, trust and history live in the project's git-ignored.agent/local/lembas/(.lembas/where.agentis another tool's), and nothing is written anywhere else — not even temporary files: the TUI starts with TMPDIR there, and the TUI library's cache goes there too (the commands the agent runs keep your TMPDIR). Your logins and connections.yaml are read, never written; your config.yaml is not read. A LLeMbas instance is used for its models, chat, speech in and out and the balance only: no link,/remote, service or hub, no deletes sent, no server library, no search, fetch or embeddings through it, no account personalization, and no self-update. The instance still records each request's usage, as any API does.-ldoes not trust the project by itself; the first start asks, and the answer is kept in the local directory. A local directory the repository carries is refused,hardline_disableis ignored, and tools treat the local directory as outside the project: no tool writes there (but in its worktrees), and reading it asks as anything outside the project does. The status bar sayslocal, andlembas -l --helpexplains it.
Changed
- A running
lembas servicefollows theremote:block without a restart: roots, mode, trust, terminals andenabledare read again whenever they are used (a stat of config.yaml; parsed only when it changed). When what the instance was told changes, the link is dialled again once nothing is working, so the web UI hears the new limits. lembas servicelinks even before any folder is allowed; it then accepts no session until one is added. With remote work off or no roots it tells the instanceroots: []and refuses every session, directory and terminal; before,service runexited at once and the instance could not tell "remote off" from "not running".- Harness spec 1.0.1:
acp.mdsays so.
[1.1.0] — 2026-10-14
Added
lembas login --jsonprints the code to approve and the outcome as one JSON object per line, for a program that drives the login (LLeMbas Desktop).
[1.0.0] — 2026-10-09
The first public release of LLeMbas CLI: a terminal coding agent and project manager for any LLM API, with permission modes, git snapshots, memory and skills, knowledge bases, MCP, voice, and a link to a LLeMbas instance whose web UI can work its sessions too. Signed Linux binaries for x64 and arm64.