diff --git a/docs/RELIABILITY.md b/docs/RELIABILITY.md
index 74295f2..0b1b494 100644
--- a/docs/RELIABILITY.md
+++ b/docs/RELIABILITY.md
@@ -19,6 +19,8 @@ review_cycle_days: 21
## Service Expectations
- `kb-server` readiness requires database and Git-backed vault access.
+- `/admin` should surface the same readiness blockers and recent operational signals visible through logs and DB-backed job/event tables.
+- The Streamlit dashboard should degrade cleanly when the FastAPI backend is offline and still allow operators to launch configured start commands.
- Autosave worker should tolerate transient Git/network failures.
- `vault-sync` should converge after temporary API outages.
@@ -31,6 +33,7 @@ review_cycle_days: 21
## Reliability Signals
- API health and readiness checks.
+- Admin dashboard state for config source, readiness blockers, git state, pending batch paths, and PR visibility.
- Job/event tables for write and publish operations.
- Sync logs for pull/push loop success and retries.
@@ -39,15 +42,35 @@ review_cycle_days: 21
### DB outage (`kb-server`)
- Signal: `GET /health` stays 200 while `GET /ready` returns non-200 with DB failure detail.
+- Signal: `/admin` shows DB not ready and surfaces the same readiness error.
- Signal: API logs show database connection failures from readiness and write paths.
- Recovery check: when DB is restored, `GET /ready` returns 200 without process restart.
### Git remote / GitHub outage (`kb-server`)
- Signal: autosave or batcher logs show push/PR failures while local commits continue.
+- Signal: `/admin` PR summary shows GitHub/API errors or empty PR visibility despite queued/pushed work.
- Signal: pending API changes remain on `kb-api/*` branch until push/PR succeeds.
- Recovery check: retry loop or next batch cycle pushes and re-establishes PR state.
+### Config drift / restart-needed state (`kb-server`)
+
+- Signal: `/admin` shows updated `.env` values, but runtime behavior still reflects old DB/auth/process settings.
+- Cause: some settings are effectively startup-bound because the API process and worker initialize long-lived config or connections at startup.
+- Recovery check: restart `kb-api` and `kb-worker`, then confirm `/admin` and `/ready` reflect the expected state.
+
+### API offline but local dashboard available (`kb-server`)
+
+- Signal: Streamlit dashboard reports backend offline instead of crashing.
+- Cause: `kb-api` is down, misbound, or unreachable at the configured backend URL.
+- Recovery check: launch the derived tmux start command via the dashboard, rerun the dashboard, and confirm `/admin/api/state` responds again.
+
+### Autosave worker offline (`kb-server`)
+
+- Signal: Streamlit dashboard shows worker runtime config but autosave activity stops advancing.
+- Cause: `kb-worker` tmux session is down or was never started.
+- Recovery check: launch or restart the worker from the dashboard and confirm vault events resume.
+
### API outage (`vault-sync`)
- Signal: sync loop logs pull/push request failures and keeps retrying on interval.
diff --git a/docs/SECURITY.md b/docs/SECURITY.md
index 8f1de51..d110487 100644
--- a/docs/SECURITY.md
+++ b/docs/SECURITY.md
@@ -18,13 +18,16 @@ review_cycle_days: 21
## Auth Boundary
- API key auth is enforced by server middleware when configured (`KB_API_KEY` non-empty).
-- With auth enabled, all HTTP routes require `X-API-Key`, including `/health`, `/ready`, `/docs`, and `/openapi.json`.
+- With auth enabled, non-admin HTTP routes require `X-API-Key`, including `/health`, `/ready`, `/docs`, and `/openapi.json`.
+- `/admin` and `/admin/api/*` are intentionally exempt from `X-API-Key` so the local operator dashboard can bootstrap and operate the instance.
- With auth disabled (`KB_API_KEY` empty), requests are accepted without API-key checks.
- `KB_API_KEY` must never be committed in docs examples with live values.
## Secret Handling
-- Secrets remain in local `.env` files or deployment secret stores.
+- Preferred model: secrets such as `KB_API_KEY` and `GITHUB_TOKEN` live in deployment secret stores or process environment variables.
+- Supported local/dev model: `/admin` can write `KB_API_KEY` and `GITHUB_TOKEN` into local `.env`.
+- Admin responses must not echo stored secret values back to the browser after save.
- Docs should only reference secret names, not values.
- Generated docs must redact secrets by default.
@@ -33,12 +36,16 @@ review_cycle_days: 21
- Path traversal and absolute-path writes are denied.
- Only approved file types are writable.
- Writes from `source=api` remain review-gated through PR workflow.
+- Admin config writes change local instance configuration only; they do not authorize content writes outside existing approval boundaries.
+- Admin start/restart actions only launch derived tmux commands for the configured local checkout and sessions; they do not elevate privileges or infer a broader process manager.
## Security Review Triggers
Update this document when changing:
- auth middleware/dependency behavior
+- admin route exposure or operator trust boundary
- request validation and path sanitization
+- secret storage or secret presentation behavior in admin/config flows
- external webhook/publish execution semantics
- GitHub token scope or PR automation behavior
diff --git a/docs/exec-plans/active/admin-ui-bootstrap.md b/docs/exec-plans/active/admin-ui-bootstrap.md
new file mode 100644
index 0000000..e03e0d6
--- /dev/null
+++ b/docs/exec-plans/active/admin-ui-bootstrap.md
@@ -0,0 +1,55 @@
+---
+owner: platform
+status: draft
+last_verified: 2026-03-12
+source_of_truth:
+ - ../../../kb-server/AGENTS.md
+ - ../../../kb-server/app/main.py
+ - ../../../kb-server/app/core/config.py
+related_code:
+ - ../../../kb-server/app/api/routes
+ - ../../../kb-server/app/services
+related_tests:
+ - ../../../kb-server/tests
+review_cycle_days: 14
+---
+
+# Admin UI Bootstrap
+
+## Objective
+
+Add an initial admin surface to `kb-server` for setup, configuration, and operational visibility without changing the core note-writing workflow.
+
+## First Slice
+
+Ship a minimal but real `/admin` experience that provides:
+
+- current configuration visibility for key settings
+- write support for local `.env` configuration updates
+- write-only secret update inputs for `KB_API_KEY` and `GITHUB_TOKEN`
+- readiness and vault/git status summary
+- recent jobs, vault events, and publish runs
+- visibility into pending `kb-api/*` PR state when GitHub is configured
+
+## Non-Goals
+
+- no note editing UI
+- no browser-triggered host provisioning
+- no direct mutation of PR approval semantics
+- no requirement to store secrets in `.env`
+
+## Design Constraints
+
+- The admin UI is an operator surface layered on top of existing API and worker behavior.
+- Existing API-key middleware remains in force when `KB_API_KEY` is configured.
+- Secret values are never returned in API responses after save.
+- Config writes update `.env`, but operators should be told that process restart may be required for full effect.
+- The UI should degrade cleanly when GitHub is unconfigured or the vault/db is unavailable.
+
+## Delivery Plan
+
+1. Add admin service helpers for status aggregation and `.env` persistence.
+2. Add `/admin`, `/admin/api/state`, and `/admin/api/config`.
+3. Render a lightweight in-app dashboard with setup and status sections.
+4. Add focused tests for config persistence and admin endpoints.
+5. Update README with usage and restart expectations.
diff --git a/docs/generated/api-surface.md b/docs/generated/api-surface.md
index 0e7664f..7d37181 100644
--- a/docs/generated/api-surface.md
+++ b/docs/generated/api-surface.md
@@ -1,11 +1,12 @@
---
owner: platform
status: generated
-last_verified: 2026-03-07
+last_verified: 2026-03-12
source_of_truth:
- ../../kb-server/app/api/routes/health.py
- ../../kb-server/app/api/routes/notes.py
- ../../kb-server/app/api/routes/publish.py
+ - ../../kb-server/app/api/routes/admin.py
related_code:
- ../../scripts/generate_context_artifacts.py
related_tests:
@@ -15,7 +16,7 @@ review_cycle_days: 7
# API Surface (Generated)
-Generated on `2026-03-07` from route handlers.
+Generated on `2026-03-12` from route handlers.
| Method | Path |
| --- | --- |
@@ -26,5 +27,12 @@ Generated on `2026-03-07` from route handlers.
| `PUT` | `/{path:path}` |
| `DELETE` | `/{path:path}` |
| `POST` | `/publish` |
+| `GET` | `/admin` |
+| `GET` | `/admin/api/state` |
+| `POST` | `/admin/api/config` |
+| `POST` | `/admin/api/start` |
+| `POST` | `/admin/api/restart` |
+| `POST` | `/admin/api/start-worker` |
+| `POST` | `/admin/api/restart-worker` |
Do not edit manually. Regenerate with `python3 scripts/generate_context_artifacts.py`.
\ No newline at end of file
diff --git a/docs/generated/env-catalog.md b/docs/generated/env-catalog.md
index e09f48d..d8a6921 100644
--- a/docs/generated/env-catalog.md
+++ b/docs/generated/env-catalog.md
@@ -1,7 +1,7 @@
---
owner: platform
status: generated
-last_verified: 2026-03-07
+last_verified: 2026-03-12
source_of_truth:
- ../../kb-server/.env.example
- ../../kb-server/app/core/config.py
@@ -16,7 +16,7 @@ review_cycle_days: 7
# Environment Catalog (Generated)
-Generated on `2026-03-07` from settings and env sources.
+Generated on `2026-03-12` from settings and env sources.
## kb-server `.env.example`
@@ -36,6 +36,9 @@ Generated on `2026-03-07` from settings and env sources.
| `GITHUB_REPO` | `owner/repo` |
| `QUARTZ_BUILD_COMMAND` | `` |
| `QUARTZ_WEBHOOK_URL` | `` |
+| `ADMIN_TMUX_SESSION` | `kb-api` |
+| `ADMIN_TMUX_WORKER_SESSION` | `kb-worker` |
+| `ADMIN_TMUX_WORKDIR` | `/absolute/path/to/flight-deck/kb-server` |
| `API_HOST` | `0.0.0.0` |
| `API_PORT` | `8000` |
@@ -57,6 +60,9 @@ Generated on `2026-03-07` from settings and env sources.
| `git_pull_interval_seconds` | `60` |
| `quartz_build_command` | `""` |
| `quartz_webhook_url` | `""` |
+| `admin_tmux_session` | `"kb-api"` |
+| `admin_tmux_worker_session` | `"kb-worker"` |
+| `admin_tmux_workdir` | `Path("/srv/flightdeck/kb-server")` |
| `api_host` | `"0.0.0.0"` |
| `api_port` | `8000` |
diff --git a/docs/generated/stale-docs-report.md b/docs/generated/stale-docs-report.md
index ef74303..7217f11 100644
--- a/docs/generated/stale-docs-report.md
+++ b/docs/generated/stale-docs-report.md
@@ -1,7 +1,7 @@
---
owner: platform
status: generated
-last_verified: 2026-03-07
+last_verified: 2026-03-12
source_of_truth:
- ../../scripts/docs_garden.py
related_code:
@@ -14,7 +14,7 @@ review_cycle_days: 7
# Stale Documentation Report
-Generated: `2026-03-07`
+Generated: `2026-03-12`
## Ownership Summary
diff --git a/docs/product-specs/kb-server.md b/docs/product-specs/kb-server.md
index ce86721..65f2cf4 100644
--- a/docs/product-specs/kb-server.md
+++ b/docs/product-specs/kb-server.md
@@ -4,13 +4,16 @@ status: verified
last_verified: 2026-03-07
source_of_truth:
- ../../kb-server/app/api/routes/notes.py
+ - ../../kb-server/app/api/routes/admin.py
- ../../kb-server/app/services/current_view_service.py
- ../../kb-server/app/core/config.py
related_code:
- ../../kb-server/app/services/git_batcher.py
+ - ../../kb-server/app/services/admin_service.py
- ../../kb-server/app/workers/autosave.py
related_tests:
- ../../kb-server/tests/test_current_view.py
+ - ../../kb-server/tests/test_admin.py
- ../../kb-server/tests/test_source_and_delete.py
review_cycle_days: 14
---
@@ -30,18 +33,31 @@ Provide a file-first API over a Git-backed vault with explicit approval boundari
- `source=api` for PR-based pending writes
- `source=human` for direct approved writes
- Writes to `view=current` are rejected.
+- `GET /admin` exposes an operator-facing setup and status surface.
+- `GET /admin/api/state` returns admin config/status state for the local instance.
+- `POST /admin/api/config` writes local configuration updates to `kb-server/.env`.
+- `POST /admin/api/start` launches the derived tmux start command for the API.
+- `POST /admin/api/restart` launches the derived tmux restart command for the API.
+- `POST /admin/api/start-worker` launches the derived tmux start command for the autosave worker.
+- `POST /admin/api/restart-worker` launches the derived tmux restart command for the autosave worker.
+- `app/streamlit_admin.py` provides an operator dashboard backed by the admin API.
## Approval Model
- API-origin changes are batched to daily `kb-api/*` branches and PRs.
- Human-origin changes go to base branch directly.
- Mainline approval remains controlled by maintainers.
+- The admin UI is not a note-editing surface and does not bypass PR-based approval for content changes.
## Guardrails
- Allowed file extensions: `.md`, `.markdown`, `.txt`.
- No absolute paths and no traversal outside vault root.
-- API key auth enforced when configured.
+- API key auth is enforced on non-admin API routes when configured.
+- Admin routes are intentionally available without `X-API-Key` so the local dashboard can bootstrap and operate the instance.
+- Admin config writes are local instance management actions only; operators must still provision the DB, vault repo, and host runtime outside the browser.
+- Admin runtime control derives the API and worker tmux commands from `ADMIN_TMUX_SESSION`, `ADMIN_TMUX_WORKER_SESSION`, `ADMIN_TMUX_WORKDIR`, `API_HOST`, and `API_PORT`.
+- Process environment variables override `.env`, including when `.env` is edited through `/admin`.
## Related Operational Docs
@@ -49,4 +65,3 @@ Provide a file-first API over a Git-backed vault with explicit approval boundari
- `../../kb-server/BRANCHING_AND_CURRENT_VIEW.md`
- `../SECURITY.md`
- `../RELIABILITY.md`
-
diff --git a/kb-server/.env.example b/kb-server/.env.example
index 2dc703a..34834de 100644
--- a/kb-server/.env.example
+++ b/kb-server/.env.example
@@ -5,6 +5,7 @@ VAULT_PATH=/Users/yashturkar/Downloads/flightdeck/vault
DATABASE_URL=postgresql://kb:kb@localhost:5432/kb
# API key — every request must include X-API-Key header when set.
+# Recommended: leave blank here and export KB_API_KEY in your shell or service env.
# Leave blank to disable auth (development only).
KB_API_KEY=
@@ -22,6 +23,7 @@ GIT_BATCH_DEBOUNCE_SECONDS=10
GIT_BATCH_BRANCH_PREFIX=kb-api
# GitHub API for PR creation (required for API write workflow)
+# Recommended: leave blank here and export GITHUB_TOKEN in your shell or service env.
# Create a token at https://github.com/settings/tokens with 'repo' scope
GITHUB_TOKEN=
GITHUB_REPO=owner/repo
@@ -30,6 +32,12 @@ GITHUB_REPO=owner/repo
QUARTZ_BUILD_COMMAND=
QUARTZ_WEBHOOK_URL=
+# Streamlit dashboard tmux control
+# The dashboard derives API/worker start/restart commands from these values.
+ADMIN_TMUX_SESSION=kb-api
+ADMIN_TMUX_WORKER_SESSION=kb-worker
+ADMIN_TMUX_WORKDIR=/absolute/path/to/flight-deck/kb-server
+
# API
API_HOST=0.0.0.0
API_PORT=8000
diff --git a/kb-server/AGENTS.md b/kb-server/AGENTS.md
index e941a3c..e10b98f 100644
--- a/kb-server/AGENTS.md
+++ b/kb-server/AGENTS.md
@@ -134,6 +134,81 @@ python3 -m pytest tests/test_git_service.py tests/test_git_batcher.py
2. Document in `.env.example`
3. Update `README.md` environment variables table
+## Logged Proposals
+
+### Admin / Management Web UI
+
+Requested scope:
+- Initial setup flow for required configuration
+- UI for viewing and editing relevant configuration values
+- Vault and Git/repo configuration visibility
+- Status dashboard for API, worker, health, jobs, and recent failures
+- Visibility into pending PR workflow state and recent automation activity
+
+Intent:
+- This is an admin surface for setup, operations, and debugging
+- This is not a content editing UI for notes
+- Content-affecting actions must continue to respect the PR-based workflow where applicable
+
+Recommended rollout:
+1. Read-only admin dashboard
+ - Health/readiness
+ - Config validation results
+ - Vault/Git status summary
+ - Recent jobs, errors, publish runs, and worker activity
+2. Setup + config management
+ - Guided first-run setup for `VAULT_PATH`, `DATABASE_URL`, `GITHUB_REPO`, branch settings, and optional auth config
+ - Editable non-secret config with validation
+3. Workflow visibility
+ - Pending batched changes
+ - Open `kb-api/*` branches / PR state
+ - Recent sync/autosave/publish outcomes
+4. Secret management
+ - Prefer write-only secret updates
+ - Do not casually echo `KB_API_KEY` or `GITHUB_TOKEN` back to the browser
+ - Preserve support for process environment variables overriding `.env`
+
+Implementation constraints:
+- Treat the UI as an admin plane layered on top of existing API/worker behavior
+- Do not silently provision system services or host-level dependencies from the browser
+- Be explicit about which values are stored in `.env` versus provided by environment variables
+- Add strong admin authentication before exposing any state-changing operational actions
+- Update docs with the trust boundary and secret-handling model when implemented
+
+Current bootstrap behavior:
+- `/admin` is now available as an initial admin surface
+- it shows config, readiness, vault/db/git status, recent jobs/events, and PR summary
+- it can write `.env` updates for visible config fields
+- it exposes write-only inputs for `KB_API_KEY` and `GITHUB_TOKEN`
+- `app/streamlit_admin.py` provides a prettier operator dashboard over the same admin API
+- the Streamlit dashboard can derive tmux-based `kb-api` and `kb-worker` start/restart commands from `.env`
+
+Current operator flow:
+1. Start the Streamlit dashboard.
+2. If `kb-api` is offline, use the configured start command from the dashboard.
+3. Open `/admin` or use the Streamlit dashboard against the running backend.
+4. Enter non-secret instance config such as `VAULT_PATH`, `DATABASE_URL`, and `GITHUB_REPO`.
+5. Save config, which writes `kb-server/.env`.
+6. Restart `kb-api` and `kb-worker`.
+7. Reopen `/admin` or rerun Streamlit and verify readiness and integration state.
+
+Current limitations:
+- `/admin` does not provision PostgreSQL, create DB roles, or create databases
+- `/admin` does not create the notes repo or GitHub repo
+- `/admin` and Streamlit assume `tmux` is installed and only manage the API/worker processes for the configured workdir/session names
+- host-level setup still happens outside the browser
+
+Secret model:
+- Preferred: establish `KB_API_KEY` and `GITHUB_TOKEN` as process environment variables
+- Supported for local/dev use: save `KB_API_KEY` and `GITHUB_TOKEN` through the admin UI into `.env`
+- Do not treat `GITHUB_REPO` as a secret; it should normally live in `.env`
+- Process environment still overrides `.env`
+
+Admin auth model:
+- `KB_API_KEY` still protects the note and publish APIs
+- `/admin` and `/admin/api/*` are intentionally exempt from `X-API-Key` so the local dashboard can bootstrap and operate the instance
+- Treat the dashboard as a local operator surface, not an internet-facing control plane
+
## Dependencies
- Python 3.10+
diff --git a/kb-server/README.md b/kb-server/README.md
index a8afee8..c69f4de 100644
--- a/kb-server/README.md
+++ b/kb-server/README.md
@@ -8,37 +8,40 @@ File-first knowledge base server. Watches a Markdown vault, auto-commits to Git,
- Git 2.34+
- PostgreSQL 15+
+
## Quick start (development)
```bash
# Clone and enter the project
cd kb-server
-# Create virtualenv and install
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
-# Copy and edit environment
-cp .env.example .env
-# Edit .env: set VAULT_PATH, DATABASE_URL, etc.
+cp .env.example .env # edit .env
-# Create the database
-createdb kb
+# Optional secrets: prefer exporting these in your shell instead of storing them in .env
+# Non-secret repo config like GITHUB_REPO should stay in .env
+export KB_API_KEY=dev-key
+export GITHUB_TOKEN=ghp_your_token
-# Run migrations
-alembic upgrade head
+psql postgres
+CREATE ROLE kb WITH LOGIN PASSWORD 'kb';
+CREATE DATABASE kb OWNER kb; # or ALTER DATABASE kb OWNER TO kb;
+\q # to quit
-# Start the API
+python -m alembic upgrade head
python -m uvicorn app.main:app --reload
-
-# In another terminal, start the autosave worker
+# in another terminal:
python -m app.workers.autosave
```
## Vault setup
-The vault must be an existing Git repository:
+`kb-server` does not create your notes repository for you. Create the notes repo manually first, then set `VAULT_PATH` in `.env` to that existing local Git repository.
+
+Example:
```bash
mkdir -p /srv/flightdeck/vault
@@ -47,7 +50,7 @@ git init
git remote add origin git@github.com:you/your-vault.git
```
-Create the directory structure you want (these are conventions, not enforced):
+After that, point `VAULT_PATH` at this repo. The directory structure inside the repo is up to you. These folders are common conventions, but not required by the server:
```text
vault/
@@ -77,10 +80,14 @@ vault/
| `GITHUB_REPO` | (empty) | GitHub repository in `owner/repo` format |
| `QUARTZ_BUILD_COMMAND` | (empty) | Shell command to build Quartz site |
| `QUARTZ_WEBHOOK_URL` | (empty) | URL to POST after push to trigger rebuild |
+| `ADMIN_TMUX_SESSION` | `kb-api` | tmux session name used by the Streamlit dashboard to manage the API |
+| `ADMIN_TMUX_WORKER_SESSION` | `kb-worker` | tmux session name used by the Streamlit dashboard to manage the autosave worker |
+| `ADMIN_TMUX_WORKDIR` | `/srv/flightdeck/kb-server` | Absolute `kb-server` path used to build the tmux start/restart commands |
| `API_HOST` | `0.0.0.0` | API bind address |
| `API_PORT` | `8000` | API bind port |
> **Note:** Unknown env keys in `.env` are silently ignored, so extra variables won't break startup.
+> **Note:** Process environment variables override values from `.env`. Keep long-lived machine config in `.env`, including non-secret values like `GITHUB_REPO`, and prefer exporting secrets like `KB_API_KEY` and `GITHUB_TOKEN` from your shell, `tmux`, or service manager.
> **Note:** `GITHUB_TOKEN` is used for GitHub API PR calls, not for `git push/pull` auth.
> Git CLI operations run non-interactively and require preconfigured credentials (SSH key or PAT-backed credential helper).
@@ -136,16 +143,147 @@ FastAPI also exposes interactive docs:
- Swagger UI: `GET /docs`
- OpenAPI JSON: `GET /openapi.json`
+- Admin UI: `GET /admin`
+
+Streamlit dashboard:
+
+```bash
+cd kb-server
+./.venv/bin/streamlit run app/streamlit_admin.py
+```
+
+## Admin UI
+
+`/admin` is a lightweight management surface for setup and operations. The initial version includes:
+
+- current config visibility for the main `.env` fields
+- write support for updating `.env` from the browser
+- write-only secret update fields for `KB_API_KEY` and `GITHUB_TOKEN`
+- readiness, vault, database, Git, and pending PR workflow status
+- recent jobs, vault events, and publish runs
+- `kb-api` and `kb-worker` start/restart support through derived tmux commands based on `ADMIN_TMUX_SESSION`, `ADMIN_TMUX_WORKER_SESSION`, and `ADMIN_TMUX_WORKDIR`
+
+Important behavior:
+
+- The admin UI is not a note editor.
+- `/admin` and `/admin/api/*` are intentionally available without `X-API-Key` so the local dashboard can bootstrap and manage the instance.
+- Process environment variables still override `.env`.
+- Saving config writes to `.env`, but you should restart `kb-api` and `kb-worker` after changing database or auth settings.
+
+### Streamlit Dashboard
+
+The repo also includes a Streamlit dashboard backed by the same admin API:
+
+```bash
+cd kb-server
+./.venv/bin/streamlit run app/streamlit_admin.py
+```
+
+The Streamlit dashboard can:
+
+- view prettified readiness, vault, database, Git, batcher, autosave, jobs, events, publish, and PR status
+- update config values, including `GITHUB_TOKEN`
+- start and restart `kb-api` if `ADMIN_TMUX_WORKDIR` points at a valid `kb-server` checkout
+- start and restart `kb-worker` in its configured tmux session
+
+The Streamlit start/restart buttons derive the tmux commands locally and asynchronously. Users only need to set `ADMIN_TMUX_SESSION`, `ADMIN_TMUX_WORKER_SESSION`, and `ADMIN_TMUX_WORKDIR`; the dashboard builds the standard `uvicorn` and autosave commands automatically from those values plus `API_HOST` and `API_PORT`.
+
+If the FastAPI backend is offline, the Streamlit dashboard shows that state instead of crashing. You can then use the sidebar start button to launch the server and rerun the page.
+
+The dashboard also exposes dedicated autosave feedback:
+
+- whether the configured worker tmux session is currently running
+- the latest autosave job status and timestamps
+- the latest autosave commit and push SHA
+- the files included in the latest autosave run
+
+### Using Admin UI For First-Time Setup
+
+The current admin UI helps configure and validate an instance, but it does not provision host dependencies for you.
+
+Before using `/admin`, you still need to create or provide:
+
+- a running PostgreSQL instance
+- a database and DB credentials referenced by `DATABASE_URL`
+- an existing local notes repository for `VAULT_PATH`
+- a configured Git remote if you want push/PR workflows
+
+First-time setup flow:
+
+1. Fill in the minimum required `.env` values:
+ - `DATABASE_URL`
+ - `VAULT_PATH`
+ - `GITHUB_REPO` if you want PR workflows
+ - `ADMIN_TMUX_WORKDIR` pointing at this `kb-server` checkout
+ - optionally `ADMIN_TMUX_SESSION` if you do not want `kb-api`
+ - optionally `ADMIN_TMUX_WORKER_SESSION` if you do not want `kb-worker`
+2. Run migrations:
+ ```bash
+ ./.venv/bin/python -m alembic upgrade head
+ ```
+3. Start the Streamlit dashboard:
+ ```bash
+ cd kb-server
+ ./.venv/bin/streamlit run app/streamlit_admin.py
+ ```
+4. If `kb-api` or `kb-worker` is offline, use the dashboard sidebar start buttons.
+5. Open `GET /admin` or use the Streamlit dashboard against the running backend.
+6. Fill in the remaining non-secret instance config:
+ - `VAULT_PATH`
+ - `DATABASE_URL`
+ - `GITHUB_REPO`
+ - Git branch / remote settings
+ - optional Quartz settings
+7. Save the form. This writes the values to `kb-server/.env`.
+8. Restart `kb-api` and `kb-worker` from the dashboard or your tmux session.
+9. Reopen `/admin` or rerun the Streamlit dashboard and verify readiness, vault, database, Git, runtime, and PR status.
+
+What `/admin` does not do yet:
+
+- it does not create the Postgres server, role, or database
+- it does not create the notes repo for you
+- it does not create the GitHub repo or remote
+- it assumes `tmux` is installed and derives the API and worker start/restart commands from your configured workdir/session names
+
+### Secret Handling
+
+There are two supported ways to establish secrets:
+
+1. Preferred: process environment variables
+ - set `KB_API_KEY` and `GITHUB_TOKEN` outside `.env`
+ - use shell exports, `tmux` startup commands, or service-manager environment config
+ - process environment values override `.env`
+
+2. Optional: save through `/admin`
+ - the admin UI provides write-only fields for `KB_API_KEY` and `GITHUB_TOKEN`
+ - saving writes them into `kb-server/.env`
+ - the UI does not read them back after save
+
+Recommended split:
+
+- Keep in `.env`: `VAULT_PATH`, `DATABASE_URL`, `GITHUB_REPO`, and other non-secret machine config
+- Keep in process env when possible: `KB_API_KEY`, `GITHUB_TOKEN`
+
+Example:
+
+```bash
+export KB_API_KEY=your_api_key
+export GITHUB_TOKEN=your_github_token
+python -m uvicorn app.main:app --reload
+```
### Authentication
-When `KB_API_KEY` is set, **every** request (including `/health`, `/ready`,
-`/docs`, and `/openapi.json`) must include the key:
+When `KB_API_KEY` is set, non-admin API requests must include the key. That includes `/health`, `/ready`, `/docs`, `/openapi.json`, `/notes/*`, and `/publish`.
+
+Example:
```bash
curl -H "X-API-Key: YOUR_KEY" http://localhost:8000/health
```
+`/admin` and `/admin/api/*` are intentionally exempt from `X-API-Key` so the local setup and Streamlit dashboard can bootstrap the instance.
+
Requests without a valid key receive a `401` response.
When `KB_API_KEY` is left blank (development mode), no authentication is
diff --git a/kb-server/alembic/env.py b/kb-server/alembic/env.py
index a9611c3..1b83b4f 100644
--- a/kb-server/alembic/env.py
+++ b/kb-server/alembic/env.py
@@ -1,8 +1,14 @@
+from pathlib import Path
+import sys
from logging.config import fileConfig
from alembic import context
from sqlalchemy import engine_from_config, pool
+PROJECT_ROOT = Path(__file__).resolve().parents[1]
+if str(PROJECT_ROOT) not in sys.path:
+ sys.path.insert(0, str(PROJECT_ROOT))
+
from app.core.config import settings
from app.models.db import Base
diff --git a/kb-server/app/api/routes/admin.py b/kb-server/app/api/routes/admin.py
new file mode 100644
index 0000000..d30fe01
--- /dev/null
+++ b/kb-server/app/api/routes/admin.py
@@ -0,0 +1,315 @@
+from __future__ import annotations
+
+from typing import Any
+
+from fastapi import APIRouter, Depends, HTTPException, Request
+from fastapi.responses import HTMLResponse, JSONResponse
+from sqlalchemy.orm import Session
+
+from app.models.db import get_session
+from app.services import admin_service
+
+router = APIRouter(tags=["admin"])
+
+ADMIN_HTML = """
+
+
+
+
+ KB Server Admin
+
+
+
+
+
+
+
KB Server Admin
+
Setup, config, and runtime visibility for the local KB server instance.
+
+
+
+
+
+
+
+
+
System Status
+
+
+
+
+
Setup Notes
+
+
Point VAULT_PATH at an existing local Git repo.
+
Process env still overrides .env values.
+
Changing database or auth config usually requires restarting kb-api and kb-worker.