Skip to content

Releases: ali-ulu/levh

v2.35.0

Choose a tag to compare

@github-actions github-actions released this 16 Oct 15:52
c6770f3

Upgrade notes

  • Windows users: upgrade. levh serve could stay running while refusing every connection after one client dropped mid-accept (WinError 64), so every agent saw ECONNREFUSED until a manual restart. Fixed below; uvicorn>=0.36 is now required.
  • Removed: the demo-data feature — levh seed-demo, levh remove-demo, setup --demo / --real, POST /api/seed-demo and POST /api/onboarding/remove-demo. Scripts that call them must drop those calls; levh setup now always prepares an empty store.
  • New, opt-in: python -m server.supervisor keeps a git-checkout install running and fast-forwards it to main every 6 hours (LEVH_AUTO_UPDATE_HOURS, 0 turns it off). Nothing changes unless you start it.

feat: levh update and a supervisor that keeps the server up and current

  • levh update [--check] [--remote origin] [--branch main] [--json] fast-forwards the git checkout LEVH runs from. It refuses a tree with local edits to tracked files, another branch, a history upstream does not contain, or a directory that is not the checkout root (a wheel install nested in a versioned home directory is never "updated"). When pyproject.toml or uv.lock changed it reinstalls the checkout (pip, or uv pip in a uv environment without pip) and rolls back with git reset --keep if that fails. Git runs with prompts disabled and every call has a deadline that kills the whole process tree, so an unattended run cannot hang on a credential prompt.
  • python -m server.supervisor runs levh serve as its child and restarts it when it exits (with crash-loop backoff), when the port actively refuses while the process lives (the Windows listener loss), or after ten failed health probes past a ten-minute boot grace. It adopts, and never kills, a server it did not start. A lock file keeps one copy, so a logon task can launch it every few minutes. Every LEVH_AUTO_UPDATE_HOURS (default 6, 0 off) it checks for an update and, only when behind, stops the server, updates, and starts it again. Health probes go to loopback for wildcard binds and bypass any HTTP proxy. See docs/installation.md.

fix: keep the Windows listener alive after a client drops mid-accept

  • On Windows levh serve ran on uvicorn's default ProactorEventLoop, whose accept loop closes the listening socket on the first OSError from AcceptEx. WinError 64 ("the specified network name is no longer available") is raised whenever a client resets its connection before it is accepted — routine for MCP clients that time out and retry — so after one such drop the process kept running but refused every connection, and every agent saw ECONNREFUSED until someone restarted it. levh serve now passes uvicorn a SelectorEventLoop factory on Windows (server/core/event_loop.py); other platforms keep uvicorn's default. Observed on CPython 3.12.10 in production (Accept failed on a socket ... WinError 64 in the server log, then no listener) and reproduced on 3.13.13: 20 reset connections kill the proactor listener, the selector listener keeps serving. tests/test_serve_event_loop.py replays that scenario on both loops (the proactor half only on Windows, as a canary for a CPython fix).
  • The uvicorn floor rises from >=0.30 to >=0.36: custom loop factories (Config.get_loop_factory) arrived in 0.36, and an older uvicorn would fail to start levh serve on Windows with this change.
  • Running uvicorn server.api:app by hand on Windows still gets the proactor loop; pass --loop server.core.event_loop:selector_event_loop.

feat: remove the demo-data feature

  • Dropped the demo corpus and its whole surface: server/core/demo_data.py, MemoryEngine.seed_demo, MemoryOnboardingMixin's demo helpers, POST /api/seed-demo, POST /api/onboarding/remove-demo, the levh seed-demo / levh remove-demo commands, setup --demo / --real (setup now always prepares an empty store), the seed_demo_completed dogfood event, and the dashboard's "Load demo data" / "Remove demo data" onboarding buttons. Onboarding readiness is now a single path: store a real memory and connect an MCP client.
  • The read-only public-instance boundary (LEVH_PUBLIC_DEMO) is unrelated and unchanged.

fix: keep the memory drawer and the quick-add FAB clickable

  • The memory detail drawer rendered inside <main class="relative z-10">, a stacking context that sits below the sticky header (z-30). Its own z-50 could not escape it, so the header — and its Quick-capture link — painted over the drawer and swallowed clicks on Pin, Delete and Close. It is now portalled to document.body, which is what makes those controls reachable; memory-detail-drawer.test.tsx asserts the portal so a future edit cannot quietly drop it.
  • The librarian widget's FAB is position: fixed with z-index: 99999 and was pinned to the same corner as the dashboard's quick-add FAB. Every click on "Add new memory" landed on the librarian button and opened its chat instead, so the quick-capture dialog never appeared. The widget FAB now sits above the quick-add one (bottom: 96px, 80px on narrow screens), and buttons.spec.ts fails if the two overlap again.

perf: stop the model-free interference scan from freezing the event loop (#505)

  • In hash embedder mode _interference_candidates scores a new memory against every stored one, and each comparison scanned the full content vocabulary of both texts with _stem_matches. On a store of ~500 source documents (avg 16 KB) one store() spent 47 s on the event loop, so an auto-feed ingest pinned a CPU core and the dashboard stopped answering. similarity_expanded now indexes the content words by their _MIN_STEM_LENGTH opening prefix, so a term only compares against the words that can actually share its stem. The filter is exact — every comparison the flat scan would have made still runs — and a full scan drops from ~4.2 s to 0.09 s (~43×). Scores are bit-identical: differential fuzzing over 10 000 random pairs (Turkish text, short tokens, random synonym expansions) found no difference.

fix: serve the complete dashboard export, not a stale bundle-less one (#507)

  • _dashboard_dir accepted any candidate with an index.html and an _next/static directory. A checkout that built the export once keeps that _next beside newer committed HTML, so the referenced content hashes are gone: / answered 200 while the chunks 404'd and React never hydrated, and routes whose chunk was missing rendered "Something went wrong" — the dashboard's buttons did nothing because the page never came up. _missing_dashboard_assets now reads every HTML file in a candidate and confirms each referenced _next/static bundle is present; only a complete export is chosen, and the packaged server/dashboard (which always ships its bundles) is served instead of the partial one. frontend/e2e/start-server.sh runs the same check before deciding whether to rebuild.

fix: stop the conflict list from 500ing on a concurrent rebuild

  • insert_conflict_if_absent now uses INSERT OR IGNORE instead of a read-then-insert. Two freshness reads can each trigger a derived-state rebuild at once (only the background pass is coalesced), and the check-then-insert race let both see a candidate pair as absent and then collide on its primary key. The loser raised UNIQUE constraint failed: memory_conflict_candidates.id, turning /api/conflicts into a 500 that the dashboard's Conflicts page hit on load. The observable contract is unchanged: an existing row — any status — is left untouched.

fix: make the dashboard's Copy buttons work outside localhost

  • Added copyText (frontend/src/lib/clipboard.ts): it prefers navigator.clipboard.writeText and falls back to a hidden-textarea execCommand("copy") when that API is missing (a plain-HTTP LAN origin) or rejects the write (NotAllowedError). The Settings, Projects and Onboarding copy buttons now report success truthfully instead of throwing and silently doing nothing.

fix: serialize explicit write transactions against a derived-state rebuild

  • Every write path shares one aiosqlite connection, and a derived-state rebuild pass holds an implicit transaction open between its first DELETE and its commit. A hard-delete or a snapshot restore issuing BEGIN IMMEDIATE in that window raised sqlite3.OperationalError: cannot start a transaction within a transaction. The startup warm task added in #503 made a background pass overlap a request's transaction routine, so the failure moved from rare to about one run in three. Database.transaction now holds a write_lock across an explicit transaction, and the rebuild holds the same lock for its whole pass, turning the interleave from a race into an invariant. The retry backoff sleep stays outside the lock, so a failing pass cannot hold writers off for the backoff duration.

fix: stop a pre-restore safety backup from deadlocking a derived-state rebuild

  • create_safety_backup now takes write_lock for the duration of the SQLite online backup. Connection.backup is queued on the shared connection like any other statement, but its worker-thread call retries in 250 ms sleeps until SQLite reports it done, so it can outlive the statements queued around it. A backup queued while a rebuild held write_lock sat ahead of the rebuild's own queued commit, and neither could run: /api/restore wedged forever with no error and no timeout. A replace restore takes the backup on its way into the same transaction, so the two are exactly the paths that meet.

v2.34.0

Choose a tag to compare

@github-actions github-actions released this 11 Oct 23:05
95dec5b

federation: bring the dashboard into the pull-first transport (#498)

  • Added POST /api/v1/federation/pull — the server-side twin of the federation-pull CLI command. Fetches one signed envelope from an explicit peer URL, verifies it locally with LEVH_FEDERATION_KEY_PATH (the key never leaves the server), and admits its memories through the existing admission gate. CLI security contracts carried over verbatim: token auth requires HTTPS on remote peers, no redirects, optional expected_node_id pin, verification completes before any write.
  • Added a Settings → Federation dashboard card: peer URL + optional expected-node inputs, a pull button, verified-envelope provenance and the admission-gate counter grid (imported / redacted / duplicates / held / errors). Full TR/EN i18n.
  • The dashboard endpoint builds its request URL only from an operator-approved LEVH_FEDERATION_PEERS allowlist — a browser session can never point this server at an arbitrary host (SSRF boundary, CodeQL-flagged and fixed before merge).
  • Documented the new route in the API reference so the docs-match-code guard stays green.

chore: prune unused frontend components and stale automation prompts (#496, #497)

  • Removed five dead frontend components (fading-memories, memory-result-card, three unused ui primitives) and two stale LEVH automation prompt files; no behavior change.

v2.33.0

Choose a tag to compare

@github-actions github-actions released this 06 Oct 22:55
88d4713

fix: anchor the antonym conflict signal to a shared topic

  • Bare antonym words ("keep" in one memory, "drop" in another) no longer open a conflict candidate on their own: the antonym signal now also requires a shared topic term in both texts, mirroring the decision-conflict lane.
  • Same-subject opposition ("keep the cache table" vs "drop the cache table") still fires; unrelated passages stay silent.
  • The next conflict rescan automatically prunes open noise rows that no longer fire; reviewed verdicts are never reset.

federation: add explicit pull-first peer transport (#484)

  • Added a source endpoint that serves the existing signed B0 federation envelope using configured node identity/signing key and the normal API authentication boundary.
  • Added levh federation-pull for explicit receiver-initiated exchange: optional token-file authentication, no redirect following, HTTPS required when sending a token to a remote peer, signature/node verification before opening the local store, and admission-gated import.
  • Kept federation transport deliberately narrow: no background polling, push, CRDT/shared store, or automatic conflict merge.

federation: prove cross-instance recall quality (#488)

  • Added a two-instance quality proof: a signed peer envelope imported through the verified boundary is recallable on the receiver, decays on the receiver's clock (pin cleared, counters reset, access time re-stamped), and never displaces a pinned local memory.
  • Exposed the proof as a content-free federation section in the offline evaluation report (levh eval run).

feat: add the memory assistant chat

  • Added /assistant, an embedded Opengeni chat that answers from the local store: the proxy recalls memories for each message, attaches them as model context, and the agent cites what it used.
  • Implemented Opengeni's session-proxy contract for the FastAPI backend so the organization key stays server-side and the browser only talks to /api/opengeni/*.
  • Chats use an installation-scoped upstream identity, the agent has no workspace tools, and recall is read-only with reinforce=False.
  • Forwarded only the conversation surface and kept uploads, artifacts, voice, model selection, forensic reads, and cancel disabled.
  • The assistant stays off until LEVH_OPENGENI_API_KEY is configured; its UI copy now ships in both English and Turkish.

continuity: lock client delivery channels to runtime registries (#486)

  • Added a code-backed client × channel matrix for stderr emission, native session-start hooks, and the MCP continuity tool/start directive.
  • Added a drift test that derives the matrix from the MCP platform registry, native hook registry, minimal tool tier, and shared MCP instruction.
  • Corrected README claims so only Claude Code is described as having an installer-owned native SessionStart hook; stderr emission is no longer presented as proof of client consumption.

i18n: ship Turkish UI locale and switcher (#481)

  • Added a complete Turkish catalogue in frontend/src/lib/i18n/tr.json, kept en as the default/fallback locale, and added parity coverage so both catalogues carry the same keys and interpolation variables.
  • Added an English/Türkçe header switcher backed by localStorage key levh_locale; the selection survives reloads and updates the document language without adding locale route segments or request-time negotiation.
  • Kept the static export architecture unchanged and added unit/E2E coverage for Turkish translation, fallback, persistence, and reload behavior.

docs: reconcile frontend i18n rollout status (#479)

  • Updated the internal roadmap to record that English-copy extraction is complete through #478 while the multi-language report item remains open because only en ships.
  • Updated the i18n design record so the sequencing/status text matches the completed surface rollout and points the next product step at a second locale plus switcher/persistence.

i18n: make build-time metadata server-safe (#477)

  • Split pure catalogue translation into src/lib/i18n/translate.ts so build-time/server code can translate without importing the client hook.
  • Kept @/lib/i18n compatible by re-exporting translate and DEFAULT_LOCALE, while useT() remains client-only.
  • Routed root layout title, description, and application name through the catalogue; its UI-string ratchet drops from 4 to 1, leaving only the technical afterInteractive Script strategy token.
  • Added coverage for the server-safe metadata path and updated the i18n design record.

i18n: move Memory Detail Drawer copy into the catalogue (#475)

  • Drawer actions/accessibility, trust, retention, metadata, score-breakdown, chart-tooltip, formula, and related-memory copy now resolve through useT().
  • Dynamic memory/trust/score/relationship values remain runtime data; the UI-string ratchet for src/components/memory-detail-drawer.tsx drops from 75 to 11, leaving only technical locale/date-format, keyboard-navigation, and chart/style detector residuals.

i18n: move onboarding empty-state copy into the catalogue (#473)

  • Onboarding setup, demo, real-memory, MCP, dogfood, readiness, terminal, status, confirmation, label, and accessibility copy now resolves through useT().
  • Dynamic server values remain runtime data; command snippets remain technical literals. The UI-string ratchet for src/components/onboarding-empty-state.tsx is provisionally tightened from 44 to 2.

i18n: move the Projects page into the catalogue (#471)

  • Projects page/empty-state/dialog/action/help/error/count/date copy now resolves through useT().
  • Project names, context filenames/content, format names, internal sentinels, locale/key identifiers, MIME values and CLI/MCP commands remain runtime/technical data; the UI-string ratchet for src/app/projects/page.tsx drops from 43 to 7, leaving only technical/internal detector residuals.

i18n: move the Visualize insights page into the catalogue (#469)

  • Insights/trust copy, chart titles/subtitles, chart series display names, empty/loading states, memory layer labels, durability bucket labels, and project/date fallbacks now resolve through useT().
  • API values, trust enum values, chart field keys, and Recharts configuration remain runtime/technical data. The UI-string ratchet for src/app/visualize/page.tsx drops from 39 to 12, leaving only Recharts/style/configuration detector false positives.

i18n: move the Home dashboard into the catalogue (#467)

  • Home hero/status copy, metric cards, recent-memory labels, knowledge/network panels, briefing copy, conflict/review signals, empty states, and relative-time copy now resolve through useT().
  • Memory/entity/project/source/status values and API data remain runtime data; locale/formatting enum tokens remain technical. The UI-string ratchet for src/app/page.tsx drops from 39 to 0.

i18n: move the Memories page into the catalogue (#465)

  • Memories page/search/filter/empty-state/edit-dialog/action/relative-time/delete-confirm copy now resolves through useT().
  • Memory/project/source/tag/session values and enum values remain runtime data; locale and non-UI diagnostics remain technical. The UI-string ratchet drops from 38 to 3, leaving only technical locale/diagnostic/class-token residuals.

i18n: move Connectors settings into the catalogue (#463)

  • Connector descriptions/categories, server-offline guidance, upload/import/sync result copy, field/action labels, and sync-history copy now resolve through useT().
  • Connector ids, config keys, path/file examples, commands, job/status enums, locale ids, and API values remain technical/runtime data; the UI-string ratchet entry for src/app/settings/_sections/connectors.tsx drops from 34 to 2, leaving only the technical levh serve command and en-GB locale literal.

i18n: move Memory Quick Add into the catalogue (#461)

  • Memory Quick Add template labels/prompts/examples, dialog/accessibility copy, capture fields, pin/action copy, and fallback error now resolve through useT().
  • Template ids/tags, source/memory-type values, hash target, and keyboard event keys remain technical/runtime data; the UI-string ratchet for src/components/memory-quick-add.tsx is provisionally tightened from 30 to 2 for the two Enter key literals.

i18n: move the Mistake Guard page into the catalogue (#459)

  • Guard heading/subtitle, refresh/error/empty states, rule/incident headings and counts, task labels, severity display/filter labels, empty-filter copy, and table headings now resolve through useT().
  • record_mistake remains a technical tool identifier and rule/violation/project/source/tool/date values remain runtime data; the UI-string ratchet entry for src/app/guard/page.tsx drops from 20 to 0.

i18n: move the Agents page into the catalogue (#457)

  • Agents loading/headings, stat labels/help, relative-time copy, breakdown counts, activity/checkpoint empty states, project/connectivity/status copy, and connection/session counts now resolve through useT().
  • Agent names, API routes, icon-map keys, project/checkpoint/runtime values remain technical/runtime data; the UI-string ratchet for src/app/agents/page.tsx is provisionally tightened from 20 to 1 for the non-UI console diagnostic.

i18n: move the People page into the catalogue (#455)

  • People list/detail headings, summaries, search, empty-state guidance, memory counts, last-seen copy, ask action/fallback, and detail headings now resolve through useT().
  • Dynamic person/memory/email/date/source values remain runtime data; the UI-string ratchet for src/app/people/page.tsx is tightened from 19 to 5, leaving three connector identifiers and two source-normalization literals.

i18n: move the Findings page into the catalogue (#453)

  • Findings tabs, heading/subtitle, refresh/empty state, occurrence/timeline/note copy, note placeholder, and review/delete actions now resolve through `...
Read more

v2.32.0

Choose a tag to compare

@github-actions github-actions released this 26 Sep 00:39
aee453e

Frontend toolchain: Tailwind v4, ESLint 9, Next 16 (#188, #186, #189)

  • Tailwind CSS upgraded to v4: PostCSS plugin moved to @tailwindcss/postcss,
    @tailwind directives replaced with @import "tailwindcss" + @config to
    preserve the existing shadcn-style TS theme; autoprefixer dropped (built-in).
  • ESLint upgraded to v9 with eslint-config-next v16; legacy .eslintrc.json
    replaced by flat eslint.config.mjs. The one genuine react-hooks/immutability
    finding (agents page) was fixed; the 23 set-state-in-effect findings are
    disabled pending a dedicated refactor of the prop-to-state sync idiom.
  • Next.js upgraded from 15.5 to 16.3.

mcp constraint widened to <3 (#184)

  • mcp>=1.0,<2 broadened to mcp>=1.0,<3 in pyproject.toml; uv.lock
    regenerated so uv lock --check passes. The locked mcp version is unchanged.

Next 16 regressions fixed: lint gate and themeColor (#256, #257)

  • next lint was removed in Next 16; next build no longer ran ESLint. Added
    an explicit npm run lint CI step and a lint script to package.json.
  • themeColor moved from the metadata export to viewport as required by
    Next 16; <meta name="theme-color"> is now present in the static output again.

The API surface is versioned and frozen as a contract (#193)

  • The same handlers are now served under /api/v1/..., and the versioned
    paths are the published contract: they are what openapi.json freezes and
    what CI checks for drift. The bare /api/... paths keep working as a
    compatibility alias but are hidden from the schema, so a client can at last
    tell a compatible edit from a breaking one. /api/health stays unversioned
    by design.

The backend has a type gate again (#195)

  • mypy now runs as a CI job over the tier of modules that is annotation-clean
    today ([tool.mypy].files in pyproject.toml). The list is a ratchet: widen
    it as modules are fixed. This restores #147's deferred type-check item,
    which #176 left without a follow-up.

The generated API docs follow the token gate (#144)

  • /docs, /redoc and /openapi.json were served without a token even when
    LEVH_TOKEN was set, because the gate only covered the /api/ prefix — an
    authenticated deployment handed any anonymous caller a complete map of all
    108 routes. A browser cannot attach X-LEVH-Token to the /docs document
    request, so the surface is now withheld (404) while a token is in force, and
    restored deliberately with LEVH_ENABLE_API_DOCS=true on a trusted network.

The process exposes Prometheus metrics (#145)

  • GET /api/metrics (and /api/v1/metrics) publishes the in-process registry
    in text exposition format: recall/store latency histograms, the embedder
    fallback and derived-rebuild counters, and the admission-verdict
    distribution. The Docker HEALTHCHECK scrapes it as well, so a process whose
    metrics surface is down no longer reads as healthy.
  • Every request gets a request_id — reused from X-Request-ID when it is a
    sane alnum/-_.: string under 128 chars, generated otherwise, echoed in the
    response header — and it is injected into each log record, which is what lets
    the recall → admission → store lines be stitched back together. With
    LEVH_LOG_JSON=1 the logs are emitted one JSON object per line instead of the
    human-readable format.
  • GET /api/readyz separates readiness from liveness: it pings SQLite, reports
    the live embedder mode and whether derived state is behind, and answers 503
    with the reasons when it is not ready.

The supply chain is pinned and audited (#146)

  • uv.lock pins the full backend graph and CI installs from it with
    uv sync --frozen, so one commit no longer resolves to a different set of
    packages weeks later; uv lock --check fails the build on a stale lock. The
    audit follows the lock too: pip-audit runs against uv export output rather
    than whatever pip happened to resolve that day, and Dependabot keeps both the
    lock and the npm graph current.
  • Releases now carry CycloneDX SBOMs for the Python and frontend artifacts, and
    a sast job runs Bandit at Medium+ so a new finding cannot land under the
    gate unnoticed.

Hook installers no longer promise a checkpoint they cannot install (#124)

  • install_claude_code_hook and install_universal_hook accepted a
    with_checkpoint argument and silently dropped it: nothing read the
    value, the CLI never defined --with-checkpoint so the path was
    unreachable, and _CHECKPOINT_TEMPLATE had no callers. The dead
    parameter and the unused template are gone, and the module docstring no
    longer advertises a periodic-checkpoint capability these hooks do not
    provide. Recurring checkpoints remain available via levh checkpoint auto.

A row the model cannot read no longer takes the store down (#267, #273)

  • A store row the model rejects — an outside agent writing
    memory_type="long_term", or a NULL id that SQLite allows on a non-INTEGER
    primary key — used to abort every startup: EpisodicMemory.get_all() raised
    out of MemoryEngine.initialize() and every other memory became unreachable.
    Such rows are now quarantined: skipped with a warning that names the row, so
    the store stays readable.
  • The store now enforces the model's own contract on INSERT and UPDATE through
    triggers generated from one rules table in the schema module (id, content,
    memory_type, importance, frequency, timestamps). A rejected write names the
    column and what the model needs, and the store file is left untouched.
  • A failed startup no longer leaves the process alive forever: the engine is
    published before initialize() and shut down in every outcome, so
    levh serve exits non-zero on startup failure instead of hanging on the
    open aiosqlite worker thread.

Quarantined rows are visible, and doctor counts them the way the read path does (#270, #272)

  • Every quarantine increments levh_memory_rows_quarantined_total in the
    Prometheus registry, and levh doctor fails on any row the current model
    cannot accept — so a store quietly rotting under an external writer produces
    a standing signal instead of passing a health review silently.
  • The doctor count now judges rows by meaning rather than storage shape:
    metadata and tags are NULL when never set, and reading those columns raw
    made every sparse row look invalid (2 genuinely unreachable rows read as 18).
    The storage-shape-to-model conversion lives in one place —
    server.core.db.memories.row_to_memory_dict — shared by the query layer and
    the doctor check, with an equivalence test pinning the two together.
  • levh doctor inspects SQLite from a running event loop, so the check no
    longer trips on the async driver it is reading through (#271).

Structured startup and static-export polish (#284, #268)

  • levh serve printed its startup banner with bare print(), so
    LEVH_LOG_JSON=1 did not make it structured even though logging.py
    advertised that path. It now routes through emit() — verbatim when JSON is
    off, a JSON record when on — and the stale docstrings describe what emit()
    is actually for (#284).
  • The static-export logo opts out of no-img-element explicitly, so the
    frontend lint gate stays green without a blanket rule change (#268).

Dependency and CI maintenance

  • Dependabot bumps across the frontend graph (vitest 2 → 5 with a vite 6.4
    floor, jsdom 25 → 30, recharts 2 → 3, @types/node 20 → 26, lucide-react,
    @testing-library/jest-dom) and the workflow graph (actions/setup-node,
    actions/setup-python, actions/upload-pages-artifact,
    astral-sh/setup-uv), plus dependabot rules that stop it opening major
    TypeScript and ESLint bumps that would need a migration of their own.

v2.31.0

Choose a tag to compare

@github-actions github-actions released this 10 Sep 19:48
852338b

Now installable, offline-first (PWA) (#86)

  • LEVH can be installed as a standalone app: manifest.webmanifest (name,
    theme color, maskable 192/512 icons), an offline-first service worker
    (sw.js, static assets cache-first, shell network-first with an offline
    fallback, API/MCP passthrough) and deferred registration
    (pwa-register.js).

Findings inbox — LEVH reports what it noticed, a human decides (#83)

  • A new inbox where internally-noticed items surface instead of disappearing.
    The dashboard lists them under Findings; each can be accepted
    (/api/findings/{id}/decide) or left. Nothing is auto-applied or deleted.

A safer, quieter librarian (#84)

  • Removed the librarian's shell authority and resolved the LLM endpoint once
    at startup instead of per unit of work.
  • Provider quota refusals are now explained (model/supplier 429) instead of
    hidden, and active agents are no longer mislabelled as silent.
  • Watchdog/event-loop robustness fixes.

Continuity briefs for every agent (#81)

  • Auto-brief and non-repeating auto-summary for all agents; a
    get_continuity_brief MCP tool with auto-inject, and the brief now leads
    with the last checkpoint.

The embedder tells you when it degrades

  • GET /api/config now reports requested_embedder_mode alongside the
    effective embedder_mode, plus embedder_fallback_reason when an
    auto → hash fallback happens, so degraded scoring is never silent.

Build & reliability

  • Pinned mcp<2 (the 2.x SDK renamed FastMCP to MCPServer), fixing CI.
  • Anchored the frontend workspace root (outputFileTracingRoot) so a stray
    package-lock.json in a user's home can no longer break local @/*
    alias resolution.
  • Docs/README hygiene: removed roadmap, demo assets, and stale references.

v2.30.0 - Universal Agent Tracking + Frontend Redesign

Choose a tag to compare

@ali-ulu ali-ulu released this 31 Aug 17:08

What's New

Universal Agent Tracking System

  • Track any AI agent with auto-heartbeats
  • Agent Activity dashboard with real-time status
  • Auto-connect hooks with continuity brief
  • Agent collaboration tools

Frontend UX Redesign

  • Memory Quick Add FAB with templates
  • Improved Memories page with tag cloud
  • Visual Connectors with category groups
  • Client selector cards

Bug Fixes

  • Admission gate holds 'review' candidates
  • Backup carries attachment bytes
  • Session deletion API
  • Windows encoding fixes

See CHANGELOG.md for full details.

LEVH 2.27.2 - human and agent memory positioning

Choose a tag to compare

@ali-ulu ali-ulu released this 17 Jul 20:54

Human and agent memory positioning

  • Updated package, API, CLI, README, landing-page, and launch metadata to describe LEVH as a local-first memory layer for AI agents and humans.
  • Added levh --version for standard CLI release identification.

PyPI: https://pypi.org/project/levh/2.27.2/

LEVH 2.27.1 — AGPL metadata alignment

Choose a tag to compare

@ali-ulu ali-ulu released this 16 Jul 22:15

License metadata alignmentnnThis patch release aligns the PyPI package metadata with the repository license: GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later).nnNo runtime behavior changes.nnValidation: release.py --check passed; full suite: 523 passed with 3 known Windows environment-specific tests excluded; wheel and sdist passed twine check.

LEVH 2.27.0 — full rename to LEVH

Choose a tag to compare

@ali-ulu ali-ulu released this 16 Jul 21:31
850d0d2

Full rename to LEVHnn- levh is now the primary CLI command; stackmemory remains as a deprecated compatibility alias with a warning.n- Added canonical LEVH_environment variables withSTACKMEMORY_ fallback support.n- Updated generated MCP configs, dashboard text, README, documentation, and tests to use LEVH-facing names.n- Preserved Python module paths, .stackmemory/, and stackmemory.db for compatibility.n`nValidation: release check PASS; targeted suite 65 passed; full suite 523 passed with 3 known Windows ENV-ISSUE tests excluded; wheel and doctor checks PASS.

LEVH 2.26.8 — first public release

Choose a tag to compare

@ali-ulu ali-ulu released this 16 Jul 19:58
592df5c

2.26.8 — Release consistency and operational hardening

  • Enforced local-first automatic embedding selection; cloud embeddings now require explicit opt-in.
  • Added SQLite durability, migration, FTS, timeout, rate-limit, backup, and connector timeout hardening.
  • Added release version consistency checks across the server, frontend, and packaged dashboard.

Full test status: 523/523 in the independent Linux reference environment. Windows has three known environment-specific issues, independent of this release.