From 5c23087cef4de3695dc07dd56fa241d99cb52868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Bene=C5=A1?= Date: Mon, 9 Nov 2026 08:18:21 +0000 Subject: [PATCH] Harness spec 3.2.0: version, README, changelog MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VERSION 3.2.0; README's file table, the `team` requirement and a 3.2.0 section; CHANGELOG Unreleased. Two tests that pinned the AGENTS.md block's absolute root now pin the relative text (context.md §11). Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 14 ++++++++++++++ harness/README.md | 35 +++++++++++++++++++++++++++++++---- harness/VERSION | 2 +- tests/instructions.test.ts | 3 ++- tests/units.test.ts | 2 +- 5 files changed, 49 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 853623f..1e17c83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,20 @@ All notable changes to LLeMbas CLI. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses [Semantic Versioning](https://semver.org/). +## [Unreleased] + +Harness spec 3.2.0, written ahead of its implementation in this CLI and in the server. + +### Added + +- **Harness spec 3.2.0.** Teams (`harness/team.md`): the agent may add members that work on their + own parts in the background and talk in the team's room, and then leads them rather than doing + the work; the tools `team_add`, `team_send`, `team_read` and `team_stop`, the size setting + (1 to 4 agents by default), reports, waiting for a free slot on a busy model. Effort levels: a + real `off` for models that can switch thinking off, and a Thinking switch where a model has only + that choice. Reasoning is sent back to the model during its turn. No absolute paths in the + prompt: paths are relative to the project root. The CLI's own implementation follows. + ## [2.0.0-beta.2] — 2026-11-07 Harness spec 3.1.0: what the model has already read stays exactly as it was, so its server diff --git a/harness/README.md b/harness/README.md index 58b4006..faa6fa7 100644 --- a/harness/README.md +++ b/harness/README.md @@ -21,10 +21,11 @@ page *Harness-parity* in LLeMbas CLI's wiki. | `permission/arity.json` | How much of a command an "always allow" covers | | `permission/defaults.json` | The rules every session starts from | | `permission/modes.json` | The four modes — manual, edit, auto, plan — as what each does with each risk class | -| `models/schema.json` | Model metadata: context, output limit, efforts, vision, tools, notes, capacity | -| `loop.json` | How one prompt runs: the step backstop, budgets, wrap-up, nudges, parallel calls, capacity; `jobs` — background work, its marks and limits; `context` — result ids, stubs, the output cap, the compaction table | +| `models/schema.json` | Model metadata: context, output limit, efforts and the thinking switch, vision, tools, notes, capacity (`parallel`); `levels` — the effort levels a chat offers and what each sends | +| `loop.json` | How one prompt runs: the step backstop, budgets, wrap-up, nudges, parallel calls, capacity; `jobs` — background work, its marks and limits; `team` — a team's size, names, marks, refusals and texts; `context` — result ids, stubs, the output cap, the compaction table, the environment lines, the session notes | | `filesystem.md` | The file system a session works in: paths, node kinds, the four access levels, errors, listings, search and indexing by tokens, stacked instruction files, skills, memory | -| `context.md` | Context hygiene: what happens to a tool result when it is inserted, and never afterwards | +| `context.md` | Context hygiene: what happens to a tool result when it is inserted, and never afterwards; the prefix that stays still; reasoning sent back during its turn; no absolute paths in the prompt | +| `team.md` | Teams: a lead and the members it adds, the size setting, the room, who receives what, reports, a manager's refusals, capacity, stopping | | `quirks.json` | What real servers do, and how both harnesses cope | | `conformance/.json` | Cases with their expected results, run by both test suites | | `acp.md` | The link between them: ACP plus every `_lembas/*` method, field and capability | @@ -47,7 +48,8 @@ page *Harness-parity* in LLeMbas CLI's wiki. page of the chat is open and attached (not a schedule, not a background job); `display`: the session is shown somewhere a file can be opened (the web UI, Desktop; not a bare terminal); `forge`: the session's view holds a repository mounted from a forge; `plan`: the session is in - plan mode. A requirement that goes away between the offer and the call makes the call answer the + plan mode; `team` (3.2.0): the session's team setting allows more than one agent, on a model that + serves two requests at once (`team.md` §2). A requirement that goes away between the offer and the call makes the call answer the tool's `unavailable` text, word for word, as its result. **From 3.1.0 a requirement that can come and go during a session does not take the tool out of the list** (`context.md` §10, rule 4): the tool is offered from the start and answers `unavailable` while the requirement is not met. @@ -66,6 +68,31 @@ page *Harness-parity* in LLeMbas CLI's wiki. approval in plan mode and answers its `unavailable` text outside it. Their permission key is `plan` (`permission/defaults.json`), which a rule written for the former `todo` key still reaches. +## 3.2.0 + +Written ahead of both implementations; both carry it in the same round. + +- **Effort levels and the thinking switch** (`models/schema.json`). `thinking_switch`: the model's + server turns thinking off for `chat_template_kwargs.enable_thinking: false`. The level `off` + exists only then, and sends that and no effort — before, `off` sent nothing, which left the model + at its server's default effort. A model that takes no efforts has the one level `default`, which + sends nothing. The levels a chat offers are `off` (with the switch) and the efforts; one level + shows no control, `[off, X]` a Thinking on/off switch, more a slider. `capacity.parallel`: how + many requests the model serves at once (`single_session` is `parallel: 1`). Conformance area + `levels`; `quirks.json` `thinking-default`; in `acp.md` an `effort` is one of these levels. +- **Reasoning goes back during its turn** (`context.md` §8): every assistant message after the last + message that started a turn carries its reasoning (`reasoning_content`; Anthropic thinking + blocks); earlier turns carry none. Area `reasoning`. +- **No absolute paths in the prompt** (`context.md` §11): an agent session's environment block names + the project and says paths are relative to its root (`loop.json` `context.env`); relative paths + resolve against the project root, absolute ones are still taken. Area `paths`. +- **Teams** (`team.md`): `team_add`, `team_send`, `team_read`, `team_stop` (shared, both, + `requires: team`); the chat setting `agents {min, max}`; the room and its marks; reports to the + manager; the size across the tree, `task` helpers included; a manager's work tools refused with a + fixed text while the tool list stays the same; members waiting for a slot past the model's + capacity; `blocks/team_lead.md` and `blocks/team_member.md`; size notes in `context.note`. Area + `team`. + ## 3.1.0 Written ahead of both implementations as `3.1.0-draft`, and `3.1.0` once both carried it (LLeMbas CLI 8e06590, LLeMbas 48e905f). **The prefix stays still** (`context.md` §10). Found on 2026-11-05 by measuring a local model's diff --git a/harness/VERSION b/harness/VERSION index fd2a018..944880f 100644 --- a/harness/VERSION +++ b/harness/VERSION @@ -1 +1 @@ -3.1.0 +3.2.0 diff --git a/tests/instructions.test.ts b/tests/instructions.test.ts index b13e6b0..84c2d2c 100644 --- a/tests/instructions.test.ts +++ b/tests/instructions.test.ts @@ -76,5 +76,6 @@ test("no instruction file anywhere on the way: the project is told to make one", mkdirSync(join(root, "a")) writeFileSync(join(paths.config, "config.yaml"), "") const system = assembleSystem({ modelRef: "s/m", family: "local", cwd: join(root, "a"), root, isGit: false, mode: "manual", planDir: join(root, ".agent", "plans"), toolNames: [] }) - expect(system).toContain(`It goes at the project root: ${root}/AGENTS.md.`) + // Spec 3.2.0 (context.md §11): the block names no absolute path. + expect(system).toContain("It goes at the project root: `AGENTS.md`.") }) diff --git a/tests/units.test.ts b/tests/units.test.ts index 8c9a70b..8079e4a 100644 --- a/tests/units.test.ts +++ b/tests/units.test.ts @@ -122,7 +122,7 @@ describe("the project's AGENTS.md", () => { const base = { modelRef: "x/y", family: "local", cwd: root, root, isGit: true, mode: "edit" as const, planDir: join(root, ".agent/plans"), toolNames: [] } const missing = assembleSystem(base) expect(missing).toContain(`This project has no AGENTS.md yet`) - expect(missing).toContain(`${root}/AGENTS.md`) + expect(missing).toContain("It goes at the project root: `AGENTS.md`.") expect(missing).toContain("which branch the work goes on") expect(assembleSystem({ ...base, isGit: false })).toContain("not a git repository yet") expect(assembleSystem({ ...base, subagent: { name: "explore", instructions: "look" } })).not.toContain("AGENTS.md yet")