The version, the changelog entry, the plan and the README. Nothing else,
which is what makes this readable as a release rather than as work.

CHANGELOG.md's 1.0.0 entry is assembled from every version below it, as
that file has said it would be since it was written: those shipped as a
running deployment rather than as releases, and this is what they add up
to. It is also what an administrator reads -- /admin/updates takes release
notes out of the annotated tag, so the tag message is this entry.

It says what arrived, then the part worth reading: the nine things that
had shipped looking correct and were found by five audit passes. Then
where the edges are, because a first release should say what it does not
do before somebody finds out.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-07 15:26:18 +02:00
parent e7294e5b20
commit dce54eb2de
4 changed files with 165 additions and 19 deletions
+70 -18
View File
@@ -4,14 +4,16 @@ Where the project is, what is deliberately not built yet, and the decisions
that would be expensive to revisit. Kept current as work lands; the detail of
*how* things work lives in [`CLAUDE.md`](CLAUDE.md).
**Status:** usable daily, and closing on 1.0.0. Streaming chat, attachments,
reasoning, tool calling with web search, custom HTTP tools and MCP servers,
agent chats that work on a machine over SSH, a knowledge library, notes, memory
and skills, speech in and out, image generation over ComfyUI, users and groups,
model administration, installable as an app, reports, messages, and scheduled
work that runs on its own. 2088 tests, `ruff` clean.
**Status:** released. **1.0.0.** Streaming chat, attachments, reasoning, tool
calling with web search, custom HTTP tools and MCP servers, agent chats that
work on a machine over SSH, helpers a reply can delegate to, a knowledge library
with keyword and semantic search, notes, memory and skills, speech in and out,
image generation over ComfyUI, users, groups, quotas and sharing, model
administration, branding, installable as an app, reports, messages, scheduled
work that runs on its own, web push, and updating from the web interface.
2283 tests on Python 3.11, 3.12 and 3.14; `ruff` clean.
What remains before the first stable release is written out below, in phases,
How it got there is written out below, in phases,
under [The road to 1.0.0](#the-road-to-100).
---
@@ -566,28 +568,47 @@ seen working.
- [x] `/healthz`, which opens the database rather than only proving the socket
is listening, and says nothing about what is here
### Phase 8 — audit and finalization (`0.9.8` … `0.9.9`)
- [ ] Security review over the whole accumulated diff
- [ ] A sweep for the failure this codebase keeps cataloguing: a control that
looks like it works — a verb against a route that does not serve it, a
trigger bound where the event does not go
- [ ] Every harness fragment read as a model would read it
- [ ] Focus, contrast and narrow widths across the admin screens
- [ ] Documentation, a fresh install, and an upgrade from an 0.8.x database
### Phase 8 — the audit, in five passes (`0.9.9` … `0.9.13`)
Five passes rather than one, each ending in a deploy. What each found is in
`CHANGELOG.md`; the shape of it is worth keeping here.
- [x] **The main logic and the harness** (`0.9.9`). Every model was being told
the time in a zone with no name; the prompt preview could not show two
thirds of what it previews; Plan mode was told to use a tool Plan mode
withdraws; reading one knowledge document could fill the whole window
- [x] **Functional bugs and unreachable features** (`0.9.10`). The four control
sweeps came back **clean** — 68 htmx verbs against 179 routes, zero
mismatches. What they found instead was one level up: folder nesting fully
built, documented in the README, and reachable by nothing; deleting a chat
leaving every file it held on disk
- [x] **Security** (`0.9.11`, `0.9.12`). Six findings. A helper could write files
and run programs unattended in a mode that promises to change nothing; an
SSH connection could be pointed at `0.0.0.0` and reach this host; **two
root escalations in the update helper**, one of which meant control of the
branch was control of root
- [x] **Testing** (`0.9.13`). 2140 tests to 2283, and four bugs that reading had
not found — three of them from driving the JavaScript under a DOM stub
- [x] Contrast, measured rather than eyeballed: `--ink-faint` failed the 4.5:1
minimum in **both** themes
- [x] Documentation, and `docs/notes/release-checklist.md` for the half a
machine cannot test
### Phase 9 — 1.0.0
- [ ] A commit that changes the version, `CHANGELOG.md`, this file and the
- [x] A commit that changes the version, `CHANGELOG.md`, this file and the
README, and nothing else
- [ ] A **signed annotated tag** whose message is the 1.0.0 changelog entry.
- [x] A **signed annotated tag** whose message is the 1.0.0 changelog entry.
Not decoration: `/admin/updates` reads release notes out of the tag
object, so the tag message is what an administrator sees on that page
- [ ] The deployment moves to the `stable` channel, which has something to
- [x] The deployment moves to the `stable` channel, which has something to
follow for the first time
---
## After 1.0.0
Features:
- **OCR** for scanned PDFs
- **Conversation branching** — `Message.parent_id` exists unused; needs a UI for
choosing between versions, which is why rewind truncates for now
@@ -597,6 +618,37 @@ seen working.
- **Writable shares**, which need history and a merge story before they need a
column
Carried out of the 1.0.0 audit, deliberately. Each is real; each would change
what something *does* rather than fix what it claims to do, which is why none of
them landed in an audit:
- **A read-only helper is still told about tools it does not have.**
`resolve_tools` filters per tool and `harness._families` gates per family, so
a family survives on its readers while its writers are gone — and seven
fragments name fifteen withdrawn write tools. The principled fix is the split
`tool.skills` / `tool.skills_write` already demonstrates, applied to `notes`,
`report`, `schedule` and `agent_edits`. That is a prompt restructure. The cost
today is bounded: `{{tool_names}}` is authoritative and the model has it, so a
helper wastes at most one round finding out.
- **`tool.background` promises a notification that can be switched off.** It has
no `requires` for `agents.background_notify`, while the runner branches on
exactly that flag. One fragment, two behaviours. Same shape as the split above.
- **`ask_user` has no harness fragment**, alone among the families. All of its
guidance lives in its schema description, which is the one thing an
administrator cannot edit.
- **`Connection.extra_headers_json` is read on every request and written by no
form**, so its documented use — OpenRouter's `HTTP-Referer` — is unreachable.
Nothing advertises it, so nothing is currently untrue.
- **Four columns are written and never read**: `Chat.compacted_at`,
`User.last_login_at`, `Schedule.last_fire_at`, `Schedule.compiled_at`. Each is
bookkeeping somebody may want to surface; none is load-bearing.
- **Dependency floor.** `pyproject.toml` pins no upper bounds and
`deploy/update.sh` runs `pip install -e` on every update, so a breaking
upstream release arrives on a button press. pip's `only-if-needed` default
limits the blast radius, which is why this is a note rather than an emergency.
- **`deploy/lxc-install.sh` has never been executed.** There is no Proxmox host
here. It is reviewed and syntax-checked; that is not the same claim.
---
## Known limits