8000 feat(assistant): answer questions about Lens itself from its docs and this server by adeelahmad · Pull Request #400 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content

feat(assistant): answer questions about Lens itself from its docs and this server - #400

Merged
adeelahmad merged 20 commits into
mainfrom
claude/project-thread-s4wlc9
Oct 18, 2026
Merged

adeelahmad merged 20 commits into
mainfrom
claude/project-thread-s4wlc9

Conversation

@adeelahmad
@adeelahmad adeelahmad commented Oct 15, 2026 •
Copy link
Copy Markdown
Owner

Requested by Adeel · project thread

Description

Before: asked "what is the MCP address?", "how do I connect Claude?" or "is Telegram on?", the assistant said the archive doesn't cover it. It only knew the archive.

After: it answers from a new lens_help tool and cites it. The tool gives this server's own facts (version; the web app, MCP and API addresses as the person is using them; remote access and HTTPS addresses when on; what is turned on; their own access; admins also get each setting's page) and the matching sections of Lens's docs, plus the docs' contents. Citations read "This Lens server" and "Docs · MCP server › Connecting"; a docs citation opens that heading. Agents get the same tool over MCP, chat rooms list its sources with their links, the tool picker offers it as the help group, and conversation exports keep a docs or server citation's source and link.

How: app/domain/manual.py cuts docs/*.md at their headings into an in-memory SQLite FTS5 index (English stemming, BM25: the word index's own engine, standard library, no model, no network), built on first use and again when a page changes (~40 ms for the whole manual). The docs are read from LENS_DOCS_DIR, else docs/ next to the code; both Docker Compose files mount the install's docs/ read-only at /docs, so the assistant reads the docs of the version it runs, and the Cloudron image copies them. Passage gains url and source, and recording_id becomes optional, so citations can point at a page instead of a recording (make openapi). The web app opens those in a new tab. The tool prompt tells the model to use lens_help for questions about Lens rather than answering from memory. MCP results from lens_help skip the injection flag, since they are Lens's own docs (which describe "ignore previous instructions" as an example).

Also fixed, found when the clicks survey hung after its first chat answer (one run in six, reproduced locally with a thread dump): a reader navigating away before a streamed answer ends leaves its generator to the garbage collector, which closes it on whatever thread is running, mid-query, and the answer's cleanup (on.end()) then waited for the one embedded database connection that same thread held, freezing every request. store.DB.conn now gives a thread the connection it already holds (tests/domain/test_store_reentrant.py closes a generator mid-query and fails in time instead of hanging). Eight local survey runs after the fix: no hang.

Motivation and Context

Adeel: the assistant had no idea about the platform, its capabilities, or general asks like the MCP address. This grounds it in Lens's docs and live instance facts through an internal tool.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change; ! in the title)

Checklist:

  • The title is a Conventional Commit.
  • My code follows the code style of this project (make hooks checks it on commit).
  • I added or updated tests (tests/api/test_lens_help.py, tests/api/test_chat_export.py, tests/domain/test_store_reentrant.py, __tests__/chat.test.tsx).
  • My change requires documentation updates, and I have updated docs/ accordingly (assistant.md "Questions about Lens itself" and the help tool group, mcp.md, configuration.md LENS_DOCS_DIR, schemas/chat-export.schema.json).
  • Users need more than the title to understand it, so I wrote it under ## Unreleased in CHANGELOG.md. n/a: the title says it.

Done questions (AGENTS.md)

  • Goal: delivers what the user wanted, merged on green CI. (merging on green)
  • Agents: lens_help is on the MCP server and in the assistant (web, voice, chat rooms, Telegram, Slack, email).
  • Zero setup: the compose files mount docs/ themselves; no new prerequisite or .env edit.
  • Fewest clicks and keystrokes: you just ask.
  • Configurable: ai.disabled_tools (Settings → AI assistant → Tools) turns it off, listed there with a label; no new setting otherwise.
  • Light: an in-memory FTS5 index of about 400 sections, a few MB, built in ~40 ms; no model call of its own.
  • Private and secure: read-only; pages picked by name from the indexed ones, never opened by path; no keys, tokens or model server addresses in the facts; settings pages only for admins. Threat model and companions list the new entry point.
  • Cost: no extra model calls; one tool round when asked about Lens.
  • User decides: read-only, changes nothing; defaults unchanged.
  • Upgrades: no stored-data shape change (old passages keep recording_id; the new fields are optional).
  • Honest: every answer from it is cited to the docs section or this server.
  • Tests, docs and generated files updated (make openapi).
  • Open standards; no new dependencies.
  • "Refine later" in DEVLOG.md: docs inside the Synology/QNAP images; an in-app docs page so citations open the installed version; docs found by meaning; docs passages for models without tools; the README overview in containers; a streamed answer's cleanup handed to a worker instead of the thread that collects it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C


Generated by Claude Code

… this server

The assistant had no idea what Lens is or does: asked for the MCP address, or
how to connect an app, it said the archive doesn't cover it. A lens_help tool
now answers from this server's own facts (version, the web app, MCP and API
addresses as the person uses them, what is turned on, their access) and from
Lens's docs, cut at their headings into an in-memory SQLite FTS5 index and
found by words. Both are cited: This Lens server, and Docs · page › section,
which opens that heading. Agents get the same tool over MCP, and chat rooms
list its sources with their links. The Docker Compose files mount docs/
read-only at /docs; Cloudron's image copies it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
@adeelahmad adeelahmad self-assigned this Oct 15, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
adeelahmad added a commit that referenced this pull request Oct 15, 2026
…pages and notes as built (#424)

Move usage analytics (#274) and assets and people (#273) out of the
README's In progress list, and add what merged since #383: a namespace's
own MCP server, chat completions and one-namespace API keys; editing and
merging entities and topics with undo, from agents too; entity pages at
wiki addresses; Connect with Google and rclone sign-in on the server;
the notes tree, today's note, pins, search and Recently deleted; backups
that keep Lens's files; and grouped, searchable settings. In progress now
lists the open feature PRs (#398, #400, #402, #408, #419), and the docs
index links usage analytics.


Claude-Session: https://claude.ai/code/session_01HDx7PPUauyjMn1LZs8JAsS

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
Web citations from main and lens_help's docs and server citations share the url passages; the Toolbox's
web app address is now web_app, since main's self.web is the web-search switch.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
Brings in #512, the fix for the upgrade check's entity count.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
Brings in the chat tool picker (#510, #511); lens_help joins it as the
"help" group (Lens's docs).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
Brings in conversation export (#474, #484). Exports keep a docs or
server citation's source (lens_help) instead of calling it a web page;
the export schema lists both.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
adeelahmad added a commit that referenced this pull request Oct 17, 2026
…525)

threat-model.yaml kept a sha256 of the whole prose, so any two pull requests
that changed threat-model.md both rewrote that one line and the second to merge
conflicted (#400, #508). The YAML's prose_version now names the prose in the
same commit, and the validator's new --base check (run by CI against the merge
commit's parent) fails a change to the prose that changes neither companion,
which is what the hash enforced, without a line every change edits. Adds tests,
including two branches that change the prose in different places merging
cleanly and still validating.

Fixes #507


Claude-Session: https://claude.ai/code/session_01Bwc5go44W4hjHKu329MepB

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
Brings in #525: prose_version no longer hashes the prose.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
The clicks survey hung after its first chat answer, one run in six: the
reader navigated away before the streamed answer ended, the garbage
collector closed the abandoned generator on the event loop's thread in
the middle of that thread's own query, and the answer's cleanup
(on.end()) waited for the one embedded connection that same thread held.
Every request then waited behind it. DB.conn now gives a thread the
connection it already holds; a test closes a generator mid-query and
fails in time instead of hanging.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
adeelahmad pushed a commit that referenced this pull request Oct 18, 2026
Ported from #400 so this PR's clicks survey passes while that lands: the
survey hung after its first chat answer when the garbage collector closed
an abandoned streamed answer mid-query on the thread holding the one
embedded connection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BHjm8NXrMmJrZH8D71s4MN
adeelahmad added a commit that referenced this pull request Oct 18, 2026
… saved ones (#539)

* fix(settings): test the LLM address and model on screen, not only the saved ones

The Test button in Settings → LLM provider tested the saved settings, so a
new address or model typed but not saved was never tried. The test route
now takes base_url, model and api_key; the saved key goes only to the saved
address.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BHjm8NXrMmJrZH8D71s4MN

* fix(store): a thread holding the embedded connection can query again

Ported from #400 so this PR's clicks survey passes while that lands: the
survey hung after its first chat answer when the garbage collector closed
an abandoned streamed answer mid-query on the thread holding the one
embedded connection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BHjm8NXrMmJrZH8D71s4MN

---------

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
Keeps both sides of the Toolbox docstring (web_app and allowed_out), and lists both the
lens help tool and deep research in the threat model's prose, JSON and YAML; the YAML had
lost the lens help entry in an earlier merge.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHrWfYDCaCbKKDX4w9at9C
@adeelahmad
adeelahmad merged commit 959787d into main Oct 18, 2026
22 checks passed
adeelahmad pushed a commit that referenced this pull request Oct 18, 2026
…-2dbl54

Also lists #400 (released in v0.15.0) as built rather than in progress, as
#536 does, so the requirements check passes again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QTanM4rqSWyCsV6x3En1N6
adeelahmad pushed a commit that referenced this pull request Oct 18, 2026
Release 0.15.0 carries #400, so the requirements check failed on main
with it still under In progress; it moves to the built list with its
checks.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ln25ykE6uBDqx21WBU94SX
adeelahmad pushed a commit that referenced this pull request Oct 18, 2026
…sed, and #400 listed as built

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTrHPwWHtEvFJFq3M1YpH4
adeelahmad pushed a commit that referenced this pull request Oct 18, 2026
Also lists the assistant's answers about Lens itself (#400, released in
v0.15.0) as built, which check_requirements now asks for.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xa7Hz2SLg6sNrGksMEzBaz
adeelahmad pushed a commit that referenced this pull request Oct 18, 2026
…is released

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH
adeelahmad pushed a commit that referenced this pull request Oct 18, 2026
adeelahmad pushed a commit that referenced this pull request Oct 18, 2026
…leased)

The same change as #575, so the requirements check passes here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ZmJ29Kc4iXuyKqCRifAH5
adeelahmad pushed a commit that referenced this pull request Oct 18, 2026
Keeps main's entity filter tests beside the feed ones, moves the web app's
Feeds note to Unreleased, and lists #400 (released in v0.15.0) as built
with its checks, which the requirements check asks for.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CDEiKGoyQX8Vmnv9bi5JpD
adeelahmad pushed a commit that referenced this pull request Oct 18, 2026
v0.15.0 released #400, so the requirements check fails while it stays
under In progress.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbBS222wEEQgkuui6CHo6c
adeelahmad pushed a commit that referenced this pull request Oct 18, 2026
#400 is released, so the requirements check wants it out of In progress
and in the built list with its checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016j3Y4Dh3DLGwyFYBH23QML
adeelahmad pushed a commit that referenced this pull request Oct 18, 2026
…rt of #578)

The requirements check fails on main since #400 was released; the same
change as #578, a no-op once that merges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SETHpH6NUGKT1Bwd6xyPCA
adeelahmad added a commit that referenced this pull request Oct 18, 2026
…tion and decide nodes (#576)

* feat(workflows): draw an automation's workflow on the canvas, with action and decide nodes

Event workflows open on the workflow canvas: What happened starts them, the
palette lists every action in the catalog, an action node's settings are
drawn from its params by SchemaForm with a badge for whether it asks first,
Decide gets a port per option and unsure, the canvas checks the leaf rule
and settings as the backend does, and Try on a sample runs the graph on a
kind's sample and says what each action would do.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjJqXgjj1cNdKGRQbX5frb

* docs(readme): list answering questions about Lens itself (#400) as built

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AjJqXgjj1cNdKGRQbX5frb

---------

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
adeelahmad pushed a commit that referenced this pull request Oct 18, 2026
adeelahmad pushed a commit that referenced this pull request Oct 18, 2026
Keeps both the publishing nodes and main's automation actions in the
workflow model, canvas and settings, and main's wording for #400.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CDEiKGoyQX8Vmnv9bi5JpD
adeelahmad added a commit that referenced this pull request Oct 18, 2026
…edule and the backup (#535)

* feat(schedules): one Schedules page for every routine, automation schedule and the backup

Lens's crontab: GET/PATCH /api/v1/schedules and POST /run, MCP tools schedules,
set_schedule and run_schedule, and an Automate > Schedules page to switch,
re-time and run anything on a clock.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwZdhpvjjidN5Y45CLSi8m

* fix(schedules): take the nav row Routines had so the phone nav fits as before

The clicks check found Admin one swipe further down on a phone with a new
nav row. Schedules now has Routines' row (the Routines page and New routine
open from its top), the routine-create journey goes through it, and
isActive marks Schedules on /routines pages.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwZdhpvjjidN5Y45CLSi8m

* fix(schedules): one New routine on the page, in its header

An empty Schedules page had New routine twice (the header and the empty
state), which made the routine-create clicks journey's link ambiguous.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwZdhpvjjidN5Y45CLSi8m

* docs(requirements): list the assistant's answers about Lens itself as built

#400 shipped in v0.15.0, so its In progress line failed make requirements on main.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NwZdhpvjjidN5Y45CLSi8m

---------

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
adeelahmad added a commit that referenced this pull request Oct 18, 2026
…secret field (#577)

* feat(web): Settings › Secrets, and a Vaultwarden picker beside every secret field

Settings › Secrets sets up the Vaultwarden vault secret fields can refer
to and tests its sign-in, and lists every field that refers to it with
whether it could be read. Every secret field gets From Vaultwarden, which
lists the vault's items by name and fills in a reference; a saved
reference shows itself and its read status, never a value.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019okSDRfFHV74BTpMzinTFg

* docs(readme): list the assistant's answers about Lens itself as built

#400 shipped in 0.15.0, so make requirements failed on main with it still under In progress.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019okSDRfFHV74BTpMzinTFg

---------

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
adeelahmad added a commit that referenced this pull request Oct 18, 2026
)

* feat(routines): graph workflows find wrong types and noise to tidy

The Find what to tidy node (candidates) looks for two more kinds: entities whose type the naming
rules read differently now (retype), and noise to hide (hide). Ask the model judges them a kind at a
time, and Apply changes makes the sure ones and proposes the rest, each undoable like a merge.
A change someone dismissed or undid is no longer found again, so a run never redoes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Nbf5G7PvMgThj8BbUPGT8

* Merge origin/main; list the assistant's Lens help (#400) as built

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Nbf5G7PvMgThj8BbUPGT8

---------

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
adeelahmad added a commit that referenced this pull request Oct 18, 2026
…ts (#563)

* feat(cli): lens ext lists, pulls, checks and pushes extension manifests

`lens ext pull` writes extensions' manifests into a folder, `push` saves the
changed ones as new versions and the new ones as extensions, `check` checks
them without saving, and `list` lists them (--json for agents). It works on
this install's database, as the first admin or --as, or on any Lens server
with --url and an API token. Pulled files carry `version: N`, so a push won't
save over changes made in Lens since, and a pull won't overwrite a file's own
changes, without --force.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FbmJ86QaV2YwusjgNowpf8

* fix(cli): lens ext pushes neither of two files with one name

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FbmJ86QaV2YwusjgNowpf8

* docs(readme): list answering questions about Lens itself as built, now #400 is released

Main's requirements check fails since v0.15.0 released #400 while the README
still listed it In progress.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FbmJ86QaV2YwusjgNowpf8

* Merge main; move the changelog entry to changelog.d

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FbmJ86QaV2YwusjgNowpf8

---------

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
adeelahmad added a commit that referenced this pull request Oct 18, 2026
…553)

* feat(mesh): run Nebula on the primary in an optional mesh container

The primary's half of the mesh: Lens's server can't create network devices,
so Nebula runs in a container of its own, `mesh` (mesh/sidecar.py in the
plain Python image), the only one holding NET_ADMIN and /dev/net/tun. It
makes this machine's key pair itself and keeps the private key in its own
volume; it puts the public key in the folder it shares with Lens's server,
and the keeper (mesh.Keeper, one process at a time on a lease) signs it and
writes the config back. The container checks each config with `nebula
-test`, reloads Nebula on SIGHUP when it can (the blocklist, the firewall)
and restarts it when it must, and relays port 8000 on the mesh address to
the database and 8080 to the API, for the machines Nebula's firewall lets
in. It fetches Nebula's release with the same pinned checksums as Lens.

Adding a node asks the upgrade agent to start the container (profile
`mesh`), and turning the mesh off stops it; GET /api/v1/mesh shows how it
runs under `service`, and the primary's row carries its report. Default
installs are unchanged: the profile is off and nothing listens.

Tested with a stand-in Nebula in CI, and with Nebula 1.11.2 in Docker: a
worker node reached the database and the API through the container, a
compute node the API only, and a removed node nothing.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTrHPwWHtEvFJFq3M1YpH4

* docs(readme): the mesh's in-progress line points at its open pull request

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTrHPwWHtEvFJFq3M1YpH4

* test(mcp): the services tool lists the mesh container too

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTrHPwWHtEvFJFq3M1YpH4

* style(mesh): the sidecar is linted and formatted as the server's code, by pre-commit too

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTrHPwWHtEvFJFq3M1YpH4

* chore: merge main; the mesh container's changelog entry under Unreleased, and #400 listed as built

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTrHPwWHtEvFJFq3M1YpH4

* chore: merge main; the mesh container's changelog entry as a fragment in changelog.d

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTrHPwWHtEvFJFq3M1YpH4

---------

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
adeelahmad added a commit that referenced this pull request Oct 18, 2026
…s graph changes to review (#560)

* feat(notifications): tell targets when a routine's run fails or leaves graph changes to review

Two new events, routine.failed and routine.proposed, sent through
Matterbridge, signed webhooks, Slack and Discord to each namespace a
routine runs over. Default events for new targets stay as they were.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AnPBc76gCvHKeWvSLd1L7h

* docs(readme): list the assistant's answers about Lens itself as built, now that #400 is released

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AnPBc76gCvHKeWvSLd1L7h

---------

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
adeelahmad added a commit that referenced this pull request Oct 18, 2026
* feat(enhance): enhance low quality images before they're read

The new enhance step, first in the standard pipeline, measures each image
(size, sharpness, noise, contrast, and face size where the namespace finds
faces) and keeps an enhanced copy of a low quality one that read, faces,
objects and descriptions then work from. The original stays as it is.

Off by default (Settings → Enhance). The classic engine (Pillow) needs
nothing; Real-ESRGAN general x4v3 (BSD-3-Clause, 5 MB ONNX) is fetched the
first time it's chosen. The copy is encrypted like the namespace's files,
re-keyed and deleted with them, and downloadable by members only.

Agents: POST /resources/{rid}/enhance, the MCP tool enhance and the enhance
automation action enhance an image on request. The web app has the settings
section, the pipeline step and an Enhance row in the Details tab.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012m72U9mPLCbuH8rSAZGSuZ

* test(imports): a transcript's import skips enhance too

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012m72U9mPLCbuH8rSAZGSuZ

* docs(threat-model): the Real-ESRGAN model the enhance step can fetch

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012m72U9mPLCbuH8rSAZGSuZ

* docs(configuration): rewrap the Settings paragraph

* docs(readme): enhancing images is built, not in progress

* docs(threat-model): list Real-ESRGAN among the dependencies

The threat model's YAML now changes with the prose, as the validator asks
since main's same-commit scheme.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012m72U9mPLCbuH8rSAZGSuZ

* docs(readme): answering about Lens itself is built, not in progress

#400 is released, so the requirements check on main was red; its In
progress line goes, and its checks join the built list.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012m72U9mPLCbuH8rSAZGSuZ

* docs(readme): keep the enhance step in the built list after merging main

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012m72U9mPLCbuH8rSAZGSuZ

---------

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
adeelahmad added a commit that referenced this pull request Oct 18, 2026
* feat(workflows): an HTTP call node behind the web tools' guard

Asset and graph workflows call a web address through netguard, as the
assistant's web tools do: public addresses on the web's ports (or
networks an admin allowed), the host written out so what flows through
can't move it, credential headers sealed to their header and host, and
a try on the canvas that only reads. Redirects now keep any credential
header, not only Authorization, from another server.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016j3Y4Dh3DLGwyFYBH23QML

* docs(readme): list the assistant's answers about Lens (#400) as built

#400 is released, so the requirements check wants it out of In progress
and in the built list with its checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016j3Y4Dh3DLGwyFYBH23QML

---------

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
adeelahmad added a commit that referenced this pull request Oct 18, 2026
* feat(timeline): emoji reactions and comments on activities

The timeline becomes a feed everyone in a namespace talks on. An opened item has a React button with a palette and shows everyone's reactions as chips; its comments open as threads with Reply, where Enter sends. A closed line sums its items' reactions and says how many comments it has. A comment on an asset's arrival is a comment on the asset, so the same thread shows on its page.

Each reaction is a reaction.added activity (noisy, by the person, with the activity as its object) and each comment a comment.added with the activity as its target, following the activity's audience, so automations and agents can act on them. Agents react and comment over MCP (react_to_activity, activity_comments, comment_on_activity) and through POST /activities/{id}/react and /activities/{id}/comments.

Reactions are one event_reaction row per person and activity, as marks are; comments reuse the comment table with an activity field. No model call is involved.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ln25ykE6uBDqx21WBU94SX

* docs(readme): list the assistant's answers about Lens itself as built

Release 0.15.0 carries #400, so the requirements check failed on main
with it still under In progress; it moves to the built list with its
checks.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ln25ykE6uBDqx21WBU94SX

* fix(chat): show a new conversation's first answer when its first load raced the stream

The page moves to /chat/{id} as a new conversation's first answer
streams. On a slow device that first load of the conversation is still
in flight when the answer ends, and the query cache folds the refetch
asked for then into the load, which predates the answer: the page showed
"No answer was saved for this question" until reloaded (the phone
clicks survey's chat-ask journey in CI). After an answer, when the
conversation read back lacks it, it is read once more.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ln25ykE6uBDqx21WBU94SX

* Revert "fix(chat): show a new conversation's first answer when its first load raced the stream"

This reverts commit 7f260ec: #582 carries
the same fix for main (refetchFresh in every chat panel, and the answer
written on a thread of its own), so this PR stays one concern.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ln25ykE6uBDqx21WBU94SX

* docs(changelog): move the reactions and comments entry to a changelog.d fragment, and name them in the README

The release commit folds Unreleased into the version section and #581 moved new entries to changelog.d/, so the
entry becomes changelog.d/timeline-social.md. The README's built line lost its reactions and comments clause in an
earlier merge; it is back.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ln25ykE6uBDqx21WBU94SX

---------

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
adeelahmad added a commit that referenced this pull request Oct 18, 2026
…ay and clipper sign-in as built (#536)

Since the last README refresh, #474, #484, #510, #511, #497, #495, #406, #516, #517,
#491, #400 and #506 merged. The README's built list now says the assistant answers
questions about Lens itself; a conversation exports as Markdown, PDF or JSON and its
answers, questions and code copy; a Tools chip picks an answer's tools, limit and
namespaces; sandbox runs open under the answer with downloads, and Settings starts the
gateway; deep research plans, runs and returns a cited report; ready-made MCP servers,
the MCP servers page and the optional containers start from the web app; and the web
clipper signs in or takes an API token. Each has its checks in docs/requirements.md.
In progress lists only open PRs; the Nebula mesh (#546, merged, partly built) moves to
Planned with what's next; the Planned proof item keeps only the Raspberry Pi timing;
the docs index links requirements and checks, and published feeds.


Claude-Session: https://claude.ai/code/session_01HDx7PPUauyjMn1LZs8JAsS

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
adeelahmad added a commit that referenced this pull request Oct 18, 2026
…ine (#538)

* feat(voice): read answers and podcasts aloud with Kokoro on this machine

Kokoro v1.0 (hexgrad's Kokoro-82M, Apache-2.0) as a text-to-speech provider, voice.tts_provider "kokoro": spoken
answers and podcast hosts are read on the server's own CPU through kokoro-onnx on ONNX Runtime, in any of its 54
voices across nine languages, with nothing sent anywhere and nothing billed. It's opt-in and fetched once it's picked:
the `kokoro` extra (espeak-ng and phonemizer are GPL-3.0, so they stay out of the default install), and the model
(voice.kokoro_model: fp32, fp16 or int8) and voices files from kokoro-onnx's release, checked against their SHA-256.
Settings → AI assistant → Voice offers it with the model size and the voice picker; a podcast's second host gets a
voice in the first host's language. kokoro.yml fetches and reads with each model on x64 and arm64.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* test(settings): carry ai.auto_title in the Kokoro settings fixture

main's conversation titles (#531) added ai.auto_title to the section the Kokoro settings test renders, so its fixture
names it too; without it Save sent an ai update beside the voice one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* docs(threat-model): count the Kokoro row in the JSON companion

The threat model workflow's validate job wants a change to threat-model.md to change a companion too (#507): the Kokoro row is documented, so the JSON's documented count goes up by one, as #518 did for Moondream.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* fix(voice): offer Kokoro in full precision and 8-bit only

On GitHub's arm64 runner, ONNX Runtime's CPU provider returned an empty waveform for kokoro-onnx's fp16 export, and kokoro-onnx's pause insertion then failed on a zero-size array. On x64 it was no faster than fp32, so voice.kokoro_model is now fp32 (the default) or int8, and the fp16 file is no longer pinned.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* test(settings): carry the research section in the Kokoro settings fixture

Main's deep research (#517) added a research section to Settings › AI assistant, so the fixture carries its defaults and Save sends only the voice change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* test(settings): carry ai.compact_at in the Kokoro settings fixture

Main added ai.compact_at (summarise long conversations early), so the fixture carries its default and Save sends only the voice change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* docs(readme): list answers about Lens itself as built, now that #400 is released

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* docs(changelog): name the Kokoro fragment after its pull request

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* docs(threat-model): count the Kokoro entries against main's newest model

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* docs(readme): take Kokoro out of In progress, now that it's built

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

---------

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants