Skip to content

Use the web management interface

Use the ZettelForge web management interface when you want a browser view for health checks, search, ingestion, entities, history, logs, and configuration. The interface is part of the self-hosted ZettelForge project. It runs as a single-tenant FastAPI app and serves a JavaScript SPA at /.

The verified startup path is local loopback access. Do not expose the web API on a network interface unless you set an API key and place it behind your normal host controls.

Prerequisites

  • ZettelForge source checkout or installation with web dependencies.
  • A terminal in the ZettelForge project root when you run python web/app.py.
  • Optional stored notes if you want non-empty search, entity, graph, and history views.

Step 1: Start the server

Start the web app on an available loopback port:

python web/app.py --port 9000

Expected startup output:

ZettelForge v2.7.0 — http://127.0.0.1:9000

Open http://127.0.0.1:9000 in your browser. If you omit --port, the CLI uses port 8088.

To disable the web interface, set ZETTELFORGE_WEB_ENABLED=false in your environment or set the web.enabled config value to false:

web:
  enabled: false

Step 2: Check the Dashboard

The Dashboard is the default route. It shows the left navigation, a header, health tiles, telemetry space, and two action buttons.

The current health API reports:

  • Version and product name.
  • Storage backend.
  • Embedding provider and model.
  • LLM provider, model, and local backend.
  • Enrichment queue depth and queue status.
  • Data directory and knowledge graph node/edge counts.

The Run Compaction and Reload Config buttons are in progress in the current SPA. Reload Config reloads displayed dashboard data. Run Compaction shows a notification only; no compaction API call was observed in the current implementation.


Step 3: Use the Search view

Open Search from the sidebar.

The view gives you three actions:

Action What it calls Verified behavior
Recall POST /api/recall Returns matching notes for a query.
Synthesize POST /api/synthesize direct_answer returns a synthesis object with answer, confidence, and sources.
Remember POST /api/remember Stores one note and returns note_id, status, entities, and latency_ms.

Use direct_answer for verified OSS synthesis behavior. The UI also displays synthesized_brief, timeline_analysis, and relationship_map format buttons, but this page does not assert OSS output for those formats.


Step 4: Use the operational views

The sidebar exposes these views:

View Current status
Knowledge Graph In progress. The API endpoints return nodes and edges, but the browser view showed an empty-graph frontend error in the current runtime probe.
Logs & Telemetry Renders log and telemetry controls. Empty environments show zero entries.
Ingest Renders single-entry, bulk, and file-ingest controls. The bulk ingest API accepts one or more items.
Entities Renders a paginated entity table with type, tier, and text filters.
History Renders recent activity with date filters and JSON export. Empty telemetry history shows zero entries.
Configuration Renders settings and YAML-editor modes. The server marks restart-required fields through /api/config/meta.

Treat empty tables as normal on a fresh data directory. Store or ingest notes first, then refresh the view.


Step 5: Configure API authentication

All API endpoints except GET / use the API guard.

With no API key configured, loopback requests from 127.0.0.1, ::1, localhost, or FastAPI testclient are allowed. Non-loopback requests are rejected until you configure an API key.

Set an API key before you expose the app beyond loopback:

export ZETTELFORGE_WEB_API_KEY=my-secret-key
curl -H "X-API-Key: my-secret-key" http://127.0.0.1:9000/api/health

The same key can be supplied as a Bearer token in the Authorization header. If you bind the CLI to 0.0.0.0 or :: without ZETTELFORGE_WEB_API_KEY, startup fails with a configuration error.

When the browser needs a key, the SPA reads zettelforgeApiKey from localStorage.


Next steps