An edge that is not drawn, and a panel that stopped eating the site
`hx-get=""` is not "fetch nothing". htmx looks for the attribute, not for a value, so the empty one the canvas rendered before a chat existed was a real request for the empty path -- which the browser resolves against the current document. Opening the canvas on the new-chat screen fetched the new-chat screen and swapped the whole site into the panel. The attribute is omitted now, and a test refuses an empty verb anywhere on the page. Which panels can exist is the server's answer; which are offered is the browser's. Both need an agent chat on a chosen connection, and before a chat exists those are controls in the composer -- so answering with the first profile offered a terminal on an ordinary chat with nothing selected. They follow `lembas:agent-target` now, and an open panel whose target goes away is closed rather than left showing one machine under another's name. `.tabs__body` is only sometimes the scroller: true where the tabs are a bounded flex child, false under the admin layout, where the page scrolls instead. So setting its scrollTop on every tab change had never once run on /admin/prompts, silently, while the reader was dragged to the bottom of a document that had just got shorter. The rule names the position now, and the handler finds the container that actually scrolls. The two top borders come off. They were what made the misalignment at the bottom of the shell visible; `--footer-height` stays, because two ends at different heights are visible without a line to prove it. The top of the shell keeps its line -- there, everything is `--header-height` and aligns by construction. And one version. pyproject carried its own copy and had drifted three minors from the one everything actually reads. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,12 +4,15 @@ 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. 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. 1824 tests, `ruff` clean.
|
||||
**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. 1824 tests, `ruff` clean.
|
||||
|
||||
What remains before the first stable release is written out below, in phases,
|
||||
under [The road to 1.0.0](#the-road-to-100).
|
||||
|
||||
---
|
||||
|
||||
@@ -369,19 +372,124 @@ be a different project, not a refactor.
|
||||
|
||||
---
|
||||
|
||||
## Not built yet
|
||||
## The road to 1.0.0
|
||||
|
||||
In the order they are likely to be worth doing.
|
||||
What is left is not another large feature. It is four kinds of work: gaps that
|
||||
read as bugs, features still owed, two structural jobs, and making this
|
||||
installable and updatable by somebody who is not its author.
|
||||
|
||||
Each phase ends the same way, and that is a requirement rather than a habit:
|
||||
tests green, `ruff` clean, `__version__` bumped (the service worker cache is
|
||||
keyed on it, so a release without a bump serves stale JavaScript), committed,
|
||||
pushed, and `deploy/update.sh` run — so the next phase starts from something
|
||||
seen working.
|
||||
|
||||
### Phase 0 — the known bugs, and the CSS (`0.8.x`)
|
||||
- [ ] **One version, one homepage.** `pyproject.toml` reads `__version__`
|
||||
instead of carrying its own copy of it, which had drifted three minors
|
||||
- [ ] **Canvas and Terminal appear only where they can work.** `hx-get=""` is an
|
||||
attribute htmx *finds*, so an empty one fetches the current document and
|
||||
swaps the whole site into the canvas panel. The buttons follow the
|
||||
composer's kind toggle and its connection, which only the browser knows
|
||||
- [ ] **The two top borders come off.** The sidebar footer and the composer sat
|
||||
either side of one vertical edge and were held to the same height so their
|
||||
borders would meet. Content scrolling under an edge that is not drawn is
|
||||
better than an edge that has to be aligned
|
||||
- [ ] **One scroll container per screen.** `.tabs` assumes it is a flex child of
|
||||
`.main`; under the admin layout it is not, so `.tabs__body` never scrolls,
|
||||
the outer container does, and switching to a shorter panel drops the
|
||||
reader at the bottom of the page
|
||||
- [ ] Sidebar scroll no longer chains to the document
|
||||
|
||||
### Phase 1 — the scheduling tools (`0.9.0`)
|
||||
- [ ] **A model can schedule.** There was no tool for it — the seam was left
|
||||
(`Schedule.origin` has defined `ORIGIN_MODEL` with no writer since
|
||||
scheduling landed) and the tool was never built, so a model asked to
|
||||
"remind me every Monday" wrote a note and said it had. `schedule_create`,
|
||||
`schedule_list`, `schedule_update` and `schedule_cancel` over the same
|
||||
`rule.validate` the form and the compile already share
|
||||
- [ ] Guidance saying which target a run should reach, and that anything which
|
||||
happens later or repeatedly is a schedule rather than a note
|
||||
|
||||
### Phase 2 — image generation admin (`0.9.1`)
|
||||
- [ ] **Defaults an administrator can set** — steps, cfg, size, sampler,
|
||||
scheduler, denoise, negative, batch. There were none: one hardcoded set
|
||||
from the SD1.5 era, and prose in a box as the only way to change it
|
||||
- [ ] The right control for each: samplers and schedulers as selects, from the
|
||||
lists ComfyUI has been discovering and nothing has been reading;
|
||||
checkpoints picked rather than typed; sizes as numbers with presets
|
||||
- [ ] A legend on the workflow editor saying what each placeholder fills and
|
||||
what type it lands as
|
||||
|
||||
### Phase 3 — subagents (`0.9.2`)
|
||||
- [ ] **A model can delegate.** A bounded, unattended agent with the parent's
|
||||
connection, directory, model and effort, whose findings come back as the
|
||||
tool result. Built on the mechanism scheduled runs already use, so it gets
|
||||
tools, rounds and budgets rather than a second loop
|
||||
- [ ] **Safe by resolution, not by instruction** — no `ask_user`, no recursion,
|
||||
read-only tools by default, and in an agent chat a mode that cannot run
|
||||
what it was not given
|
||||
- [ ] Guidance for the two uses that differ: fanning out across a research
|
||||
question, and reading a codebase
|
||||
|
||||
### Phase 4 — rebranding and customization (`0.9.3`)
|
||||
- [ ] **An instance can be somebody else's.** Name, logo, favicon and PWA icons,
|
||||
a tagline, and the Middle-earth strings as editable data — defaults in
|
||||
code and overrides in the database, so a later release still improves the
|
||||
wording nobody changed
|
||||
- [ ] Global CSS overrides, and a custom theme defined as a set of tokens rather
|
||||
than a stylesheet, since no component hard-codes a colour
|
||||
|
||||
### Phase 5 — extraction, embeddings and hybrid search (`0.9.4`)
|
||||
- [ ] **Extraction has settings** — upload size, image edge, PDF pages,
|
||||
extracted characters, orphan age, which extensions count as text
|
||||
- [ ] **A dedicated embedding model**, chosen from the models flagged for it
|
||||
- [ ] **Search becomes hybrid** — FTS5 and vector recall fused, behind the one
|
||||
call the retrieval service already is. No model chosen means exactly the
|
||||
keyword search there is today
|
||||
|
||||
### Phase 6 — permissions, quotas and sharing (`0.9.5`)
|
||||
- [ ] **"What can this user actually do?"** answered on screen, from the
|
||||
resolution that already computes it
|
||||
- [ ] Membership edited from one side; a searchable, paginated user list
|
||||
- [ ] Reading and writing split within a gate where the difference matters
|
||||
- [ ] **Quotas on a group**, resolved by maximum — the union rule applied to
|
||||
numbers — and enforced where the existing budgets are
|
||||
- [ ] Deleting a group or a user forgets its grants, which it never did
|
||||
- [ ] Sharing as its own action with a search box, a shared-with-me filter, and
|
||||
reports shareable. Sharing stays read-only
|
||||
|
||||
### Phase 7 — packaging and updating (`0.9.6`)
|
||||
- [ ] **Docker**, with the data on a volume and a TLS proxy expected in front
|
||||
- [ ] **An LXC bootstrap** that runs the existing installer in a container
|
||||
- [ ] **Updating without a shell** — a page that says what is running, what is
|
||||
available and what changed, and a button answered by an opt-in systemd
|
||||
helper, because the service user cannot restart itself and should not
|
||||
|
||||
### Phase 8 — audit and finalization (`0.9.7` … `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 9 — 1.0.0
|
||||
- [ ] A commit that changes the version, this file and the README, and tags it
|
||||
|
||||
---
|
||||
|
||||
## After 1.0.0
|
||||
|
||||
### Smaller things
|
||||
- **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
|
||||
- **Chat export** (Markdown, JSON)
|
||||
- **Semantic search** in the library — the retrieval service is one call, so an
|
||||
embedding backend can go behind it without touching the tools or the UI
|
||||
- **Archived chats** — the column exists, nothing surfaces it
|
||||
- **Per-user quotas**
|
||||
- **Several workers** — see the first known limit below
|
||||
- **Writable shares**, which need history and a merge story before they need a
|
||||
column
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user