v0.6.0

Lifecycle

Follow the daemon from launch to shutdown, and see which goroutines run concurrently in between.

Startup sequence

runServer launches the current executable with --daemon in a new session, redirects stdout and stderr to daemon.log, and polls for the endpoint file every 100 ms for up to 10 seconds. runServerDaemon then initializes in this order:

  1. Write runtime.uid with a new UID, the PID, and the start time. A failure, including another live daemon, is logged as a warning and startup continues.
  2. Initialize the keychain context for service kuradb.
  3. Construct the OpenAI embedder; a missing credential exits the process.
  4. Open global.db, preload query embeddings of the expected dimension, and register the hook that persists new query embeddings.
  5. Initialize the gse tokenizer and the process-wide vector cache.
  6. Load the database registry from db.json; a read error exits the process.
  7. For each registered database: ensure its directories and ~/Kura_{db} symlink, open data.db, create its vector bucket, and rebuild the bucket from embedded, non-dismissed rows.
  8. Start one embedding scheduler and one watcher per loaded database.
  9. Start the HTTP server on 127.0.0.1, write endpoint, and wait for SIGINT or SIGTERM.

A per-database failure before data.db opens skips that database. A vector-bucket failure leaves the database queryable by keyword but starts no watcher or embedder for it.

Concurrency model

Work Goroutines Coordination
Watcher One per loaded database, 10-second ticker Snapshot writes to record.json run in a goroutine guarded by a mutex
Embedding scheduler One per loaded database, 5-second ticker Batches of up to 64 pending chunks
Search Keyword and semantic branches run concurrently when no target is set sync.WaitGroup in search.Search, shared by all transports
Query-cache persistence One short goroutine per new query embedding 5-second timeout per write to global.db
HTTP server One listener goroutine plus a shutdown watcher Context cancellation

SQLite provides a read pool of eight connections and a separate write connection through go-sqlkit. The vector cache uses a cache-level and a per-bucket RWMutex; the query cache has its own RWMutex.

Shutdown

A termination signal cancels the shared context. Each part reacts independently:

Part Action
HTTP server Removes endpoint, then calls Shutdown with a 5-second timeout
Watchers and embedders Leave their select loops
Main goroutine Clears runtime.uid, closes every per-database connector, then closes global.db

The main goroutine does not wait for the HTTP shutdown or the loops to finish, so the process can exit before in-flight requests complete. kura stop sends SIGTERM and escalates to SIGKILL if the process is still alive after 5 seconds.

中文