Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
144 commits
Select commit Hold shift + click to select a range
400e500
Update test_artifact_content_type_and_path.py
rmusser01 Nov 2, 2025
8e73c04
Merge branch 'dev' of https://github.com/rmusser01/tldw_server into dev
rmusser01 Nov 2, 2025
27f74b7
fix
rmusser01 Nov 2, 2025
b2800ca
fixes
rmusser01 Nov 2, 2025
2129647
fixes
rmusser01 Nov 2, 2025
ccd63bf
fixes
rmusser01 Nov 2, 2025
96adaac
fixes
rmusser01 Nov 2, 2025
bc49d4c
fixes
rmusser01 Nov 2, 2025
48f9795
fixes
rmusser01 Nov 2, 2025
8d3026d
Update tldw_Server_API/app/core/TTS/adapters/openai_adapter.py
rmusser01 Nov 2, 2025
4c4e8bf
Update Docs/Getting-Started-STT_and_TTS.md
rmusser01 Nov 2, 2025
18bea9c
Update Docs/Getting-Started-STT_and_TTS.md
rmusser01 Nov 2, 2025
f3f7ad6
Update tldw_Server_API/app/core/Sandbox/service.py
rmusser01 Nov 2, 2025
5439691
Update tldw_Server_API/tests/sandbox/test_artifact_traversal_integrat…
rmusser01 Nov 2, 2025
7f93757
fixes
rmusser01 Nov 2, 2025
90e527e
Merge branch 'dev' of https://github.com/rmusser01/tldw_server into dev
rmusser01 Nov 2, 2025
9763ca2
Update openai_adapter.py
rmusser01 Nov 2, 2025
13d1030
fix
rmusser01 Nov 3, 2025
ffd1c7b
fixes
rmusser01 Nov 3, 2025
a18f8e6
fixes
rmusser01 Nov 3, 2025
9063223
fix
rmusser01 Nov 3, 2025
f5ec492
fixes
rmusser01 Nov 3, 2025
a5d3ef5
webui adds
rmusser01 Nov 3, 2025
1c9903c
Update .github/workflows/sbom.yml
rmusser01 Nov 3, 2025
4a53e49
fixes
rmusser01 Nov 3, 2025
da7ad02
Merge branch 'dev' of https://github.com/rmusser01/tldw_server into dev
rmusser01 Nov 3, 2025
bfc8aae
fixes
rmusser01 Nov 3, 2025
1486e6d
Update main.py
rmusser01 Nov 3, 2025
45ebef0
fixes
rmusser01 Nov 3, 2025
b93b11d
fixes
rmusser01 Nov 3, 2025
a6afe1f
Update circuit_breaker.py
rmusser01 Nov 3, 2025
349db3d
Update circuit_breaker.py
rmusser01 Nov 3, 2025
2245814
fixes
rmusser01 Nov 3, 2025
00f1036
stuff
rmusser01 Nov 3, 2025
a9d62ce
stuff
rmusser01 Nov 3, 2025
066917c
fixes
rmusser01 Nov 3, 2025
0d66be8
fixes + rewrites
rmusser01 Nov 3, 2025
e6a36f6
Update test_rg_capabilities_endpoint.py
rmusser01 Nov 3, 2025
79f888f
idk
rmusser01 Nov 4, 2025
96ebea9
ugh
rmusser01 Nov 4, 2025
9d84bec
ugh 2
rmusser01 Nov 4, 2025
ee86363
Sandbox+Adapter unification still WIP
rmusser01 Nov 5, 2025
8f687b5
fixes according to code rabbit
rmusser01 Nov 5, 2025
3c4abe7
Update conftest.py
rmusser01 Nov 5, 2025
599c624
fixes
rmusser01 Nov 5, 2025
3e36a12
fixes
rmusser01 Nov 5, 2025
a5e8e71
Update ci.yml
rmusser01 Nov 5, 2025
bced400
fixes
rmusser01 Nov 5, 2025
9972090
Update chat_fixtures.py
rmusser01 Nov 5, 2025
9e1a1f4
fixes
rmusser01 Nov 5, 2025
89c9ca7
fixes
rmusser01 Nov 5, 2025
c646195
Update orgs_teams.py
rmusser01 Nov 5, 2025
bd9f956
Update test_session_manager_configured_key.py
rmusser01 Nov 5, 2025
f0a84ab
Update session_manager.py
rmusser01 Nov 5, 2025
e6c46b2
Update test_l2_normalization_policy.py
rmusser01 Nov 5, 2025
55a4e9c
fix
rmusser01 Nov 6, 2025
c78b84c
fixes
rmusser01 Nov 6, 2025
069fcee
fixes
rmusser01 Nov 6, 2025
24f56a0
fixes
rmusser01 Nov 6, 2025
4e6702c
Update test_database_backends.py
rmusser01 Nov 6, 2025
33f1784
Update conftest.py
rmusser01 Nov 6, 2025
c14a69b
Update test_streaming_unified_benchmark.py
rmusser01 Nov 6, 2025
ed6319a
fix
rmusser01 Nov 6, 2025
a78f177
fix
rmusser01 Nov 6, 2025
8f08b9e
Update test_request_queue_workers.py
rmusser01 Nov 6, 2025
c6b2457
fixes
rmusser01 Nov 6, 2025
ff9ff41
fixes
rmusser01 Nov 7, 2025
566d459
benchmarking scrips
rmusser01 Nov 7, 2025
aa89995
fixes
rmusser01 Nov 7, 2025
445c358
fixes
rmusser01 Nov 7, 2025
bd4cffc
fixes
rmusser01 Nov 7, 2025
32cd014
fixes
rmusser01 Nov 7, 2025
0bab803
fixes+tts
rmusser01 Nov 7, 2025
6029568
Update test_resource_governor_endpoint.py
rmusser01 Nov 7, 2025
120a414
Update test_async_adapters.py
rmusser01 Nov 7, 2025
131f9de
fix
rmusser01 Nov 7, 2025
0dd9626
fixes
rmusser01 Nov 7, 2025
54ecd44
fixes
rmusser01 Nov 7, 2025
5b571fd
fixes
rmusser01 Nov 8, 2025
929c5ef
fixes
rmusser01 Nov 8, 2025
654828b
fixes
rmusser01 Nov 8, 2025
c289fa5
fixes
rmusser01 Nov 8, 2025
52b938e
fixes
rmusser01 Nov 8, 2025
e66993d
Update Education.md
rmusser01 Nov 8, 2025
1ac6b84
Update request_queue.py
rmusser01 Nov 8, 2025
06f5990
fixes+1st draft new user guide
rmusser01 Nov 8, 2025
846fbe2
fixes
rmusser01 Nov 8, 2025
d5e88c9
Potential fix for code scanning alert no. 920: Full server-side reque…
rmusser01 Nov 8, 2025
4c974d4
fixes
rmusser01 Nov 8, 2025
a6d4ee7
Merge branch 'dev' of https://github.com/rmusser01/tldw_server into dev
rmusser01 Nov 8, 2025
63d9177
chore: make pcm stream client executable
rmusser01 Nov 8, 2025
04f0d25
fixes
rmusser01 Nov 8, 2025
65341b4
fixe
rmusser01 Nov 8, 2025
f15c87d
fixes
rmusser01 Nov 8, 2025
ce8dc64
fixes
rmusser01 Nov 8, 2025
8248dab
tests: standardize provider tests to mock adapter http client; add pa…
rmusser01 Nov 8, 2025
3fc692f
tests: mock adapter http client across providers (openrouter/mistral/…
rmusser01 Nov 8, 2025
71b1942
adapters: normalize SSE and finalize streams for qwen/deepseek/huggin…
rmusser01 Nov 8, 2025
ad82dfd
fixes
rmusser01 Nov 8, 2025
7383a85
adapters: unify SSE normalization and finalize_stream for mistral/goo…
rmusser01 Nov 8, 2025
c83067a
adapter_shims: prefer adapter when http client seam is patched for op…
rmusser01 Nov 8, 2025
a323328
tests: fix DeepSeek to mock legacy requests path for error mapping an…
rmusser01 Nov 8, 2025
acf9eac
fixes
rmusser01 Nov 8, 2025
b1f242e
fixes
rmusser01 Nov 8, 2025
d7a9510
fixes
rmusser01 Nov 8, 2025
de1795d
fixes
rmusser01 Nov 8, 2025
3e97878
fixes
rmusser01 Nov 8, 2025
bb7c863
webui
rmusser01 Nov 8, 2025
cbfbfe5
fixes
rmusser01 Nov 9, 2025
51d69a7
webui/tts
rmusser01 Nov 9, 2025
bdc05dd
tts
rmusser01 Nov 9, 2025
87e36bf
'fixes'
rmusser01 Nov 9, 2025
3f72df3
js
rmusser01 Nov 9, 2025
34f415f
webui
rmusser01 Nov 9, 2025
b3fb41d
fixes
rmusser01 Nov 9, 2025
048239a
fixes
rmusser01 Nov 9, 2025
1913084
fixes
rmusser01 Nov 9, 2025
5cdccf9
fix
rmusser01 Nov 9, 2025
b89f1c2
fixes
rmusser01 Nov 9, 2025
e793bf0
fixes
rmusser01 Nov 9, 2025
7dfd54f
fixes
rmusser01 Nov 9, 2025
ffb5b18
Potential fix for code scanning alert no. 904: Information exposure t…
rmusser01 Nov 9, 2025
e4a3046
Potential fix for code scanning alert no. 922: Full server-side reque…
rmusser01 Nov 9, 2025
5bde366
Potential fix for code scanning alert no. 893: Information exposure t…
rmusser01 Nov 9, 2025
4a0f332
Potential fix for code scanning alert no. 788: Information exposure t…
rmusser01 Nov 9, 2025
c74b53d
Update Helper_Scripts/voice_latency_harness/harness.py
rmusser01 Nov 9, 2025
cfc9b73
Potential fix for code scanning alert no. 925: Exception text reinter…
rmusser01 Nov 9, 2025
b311945
Potential fix for code scanning alert no. 936: DOM text reinterpreted…
rmusser01 Nov 9, 2025
f3cbe53
Potential fix for code scanning alert no. 933: DOM text reinterpreted…
rmusser01 Nov 9, 2025
8edcaf4
Update tldw_Server_API/WebUI/js/simple-mode.js
rmusser01 Nov 9, 2025
dd49bf4
fxies
rmusser01 Nov 9, 2025
6361039
Potential fix for code scanning alert no. 926: Exception text reinter…
rmusser01 Nov 9, 2025
ed8407d
Update tldw_Server_API/WebUI/js/legacy-helpers.js
rmusser01 Nov 9, 2025
8606329
fixes
rmusser01 Nov 9, 2025
6e27b9a
Merge branch 'dev' of https://github.com/rmusser01/tldw_server into dev
rmusser01 Nov 9, 2025
0fe8518
Create test_rg_metrics_denial_micro.py
rmusser01 Nov 9, 2025
2e63935
fixes
rmusser01 Nov 9, 2025
c21cd15
fixes
rmusser01 Nov 10, 2025
9e59bb1
fixes
rmusser01 Nov 10, 2025
5986489
update references to newer anthropic models
rmusser01 Nov 10, 2025
1b6642a
fixes
rmusser01 Nov 10, 2025
d607229
fixes
rmusser01 Nov 10, 2025
46f40d1
webui fixes
rmusser01 Nov 10, 2025
2be045c
fixes
rmusser01 Nov 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
name: CI

on:
# Run on direct pushes to protected branches only
push:
branches:
- main
- dev
# Run CI for PRs targeting these branches
pull_request:
branches:
- main
- dev
workflow_dispatch:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
# Ensure push and PR for the same commit share one slot
group: ci-${{ github.event.pull_request.head.sha || github.sha }}
cancel-in-progress: true

jobs:
lint:
Expand Down Expand Up @@ -83,6 +88,8 @@ jobs:
TEST_DB_HOST: 127.0.0.1
TEST_DB_USER: tldw
TEST_DB_PASSWORD: tldw
# Align AuthNZ_Postgres conftest default DB name with tests
TEST_DB_NAME: tldw_test
TLDW_TEST_POSTGRES_REQUIRED: '1'
steps:
- name: Checkout
Expand Down Expand Up @@ -115,6 +122,18 @@ jobs:
run: |
echo "POSTGRES_TEST_PORT=${{ job.services.postgres.ports[5432] }}" >> "$GITHUB_ENV"
echo "TEST_DB_PORT=${{ job.services.postgres.ports[5432] }}" >> "$GITHUB_ENV"
# Provide a unified DSN so any test preferring TEST_DATABASE_URL uses the right DB
echo "TEST_DATABASE_URL=postgresql://tldw:[email protected]:${{ job.services.postgres.ports[5432] }}/tldw_content" >> "$GITHUB_ENV"
echo "DATABASE_URL=postgresql://tldw:[email protected]:${{ job.services.postgres.ports[5432] }}/tldw_content" >> "$GITHUB_ENV"

- name: Ensure base DB exists
shell: bash
env:
PGPASSWORD: tldw
run: |
PORT="${{ job.services.postgres.ports[5432] }}"
psql -h 127.0.0.1 -p "$PORT" -U tldw -d postgres -tc "SELECT 1 FROM pg_database WHERE datname='tldw_content'" | grep -q 1 || \
psql -h 127.0.0.1 -p "$PORT" -U tldw -d postgres -c "CREATE DATABASE tldw_content"

- name: Install additional deps for PG tests
run: |
Expand Down
12 changes: 10 additions & 2 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
name: CodeQL

on:
# Run on direct pushes to protected/default branches only
push:
branches: [ main, master, dev ]
branches: [ main, master ]
# Run on PRs targeting main/master/dev, not every branch
pull_request:
branches: [ '**' ]
branches: [ main, master, dev ]
schedule:
- cron: '0 6 * * 1'
# Allow manual runs
workflow_dispatch:

concurrency:
group: codeql-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
analyze:
Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/jobs-suite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ jobs:
POSTGRES_TEST_DB: tldw_content
POSTGRES_TEST_USER: tldw
POSTGRES_TEST_PASSWORD: tldw
TEST_DB_NAME: tldw_test
TLDW_TEST_POSTGRES_REQUIRED: '1'
steps:
- name: Checkout
Expand Down Expand Up @@ -131,6 +132,14 @@ jobs:
echo "POSTGRES_TEST_PORT=${{ job.services.postgres.ports[5432] }}" >> "$GITHUB_ENV"
echo "TEST_DB_PORT=${{ job.services.postgres.ports[5432] }}" >> "$GITHUB_ENV"

- name: Ensure base DB exists
env:
PGPASSWORD: tldw
run: |
PORT="${{ job.services.postgres.ports[5432] }}"
psql -h 127.0.0.1 -p "$PORT" -U tldw -d postgres -tc "SELECT 1 FROM pg_database WHERE datname='tldw_content'" | grep -q 1 || \
psql -h 127.0.0.1 -p "$PORT" -U tldw -d postgres -c "CREATE DATABASE tldw_content"

- name: Install pytest and psycopg
run: |
python -m pip install --upgrade pip
Expand Down
112 changes: 87 additions & 25 deletions .github/workflows/sbom.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,40 +21,102 @@ jobs:
- name: Checkout
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Generate Python SBOM (CycloneDX)
run: |
set -euo pipefail
python -m pip install -q cyclonedx-python
GEN_CMD="python -m cyclonedx_py"
if [ -n "${pythonLocation:-}" ] && [ -x "${pythonLocation}/bin/cyclonedx-py" ]; then \
GEN_CMD="${pythonLocation}/bin/cyclonedx-py"; \
elif command -v cyclonedx-py >/dev/null 2>&1; then \
GEN_CMD="cyclonedx-py"; \
fi
gen_from_requirements() { \
local req="$1"; \
echo "Generating Python SBOM from ${req} using ${GEN_CMD}"; \
${GEN_CMD} -r "${req}" --output-file sbom-python.cdx.json || { \
echo "Primary generator failed; attempting cyclonedx-bom fallback"; \
python -m pip install -q cyclonedx-bom || true; \
if command -v cyclonedx-bom >/dev/null 2>&1; then \
cyclonedx-bom -r "${req}" -o sbom-python.cdx.json; \
else \
python -m cyclonedx_bom -r "${req}" -o sbom-python.cdx.json; \
fi; \
}; \
}
if [ -f tldw_Server_API/requirements.txt ]; then \
gen_from_requirements tldw_Server_API/requirements.txt; \
elif [ -f requirements.txt ]; then \
gen_from_requirements requirements.txt; \
else \
echo "No requirements file found; cannot generate SBOM"; \
exit 1; \
fi

# No registry login required for public Docker Hub images used below
- name: Setup Node
uses: actions/setup-node@v6
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Generate Python SBOM from pyproject (cdxgen)
- name: Generate Node SBOM (CycloneDX NPM)
run: |
if [ -f pyproject.toml ]; then \
npx @appthreat/cdxgen -t python -o sbom-python.cdx.json; \
if [ -f package-lock.json ]; then \
npx -y @cyclonedx/cyclonedx-npm --output-file sbom-node.cdx.json; \
elif [ -f tldw-frontend/package-lock.json ]; then \
(cd tldw-frontend && npx -y @cyclonedx/cyclonedx-npm --output-file ../sbom-node.cdx.json); \
else \
echo "No package-lock.json found; skipping Node SBOM"; \
fi
Comment on lines 101 to 109
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error handling to the Node SBOM generation step for consistency.

The "Generate Node SBOM (CycloneDX NPM)" step lacks set -euo pipefail, which means if the npx command fails, the workflow will continue silently. This is inconsistent with other run blocks in this workflow (Python SBOM and merge steps both use strict error handling) and could lead to missing or incomplete sbom-node.cdx.json, which then triggers fallback logic in the merge step.

While the Node SBOM generation is intentionally optional (skipped if no package-lock.json exists), command failures should still cause the job to fail.

Apply this diff to add error handling:

       - name: Generate Node SBOM (CycloneDX NPM)
         run: |
+          set -euo pipefail
           if [ -f package-lock.json ]; then \
             npx -y @cyclonedx/cyclonedx-npm --output-file sbom-node.cdx.json; \
           elif [ -f tldw-frontend/package-lock.json ]; then \
             (cd tldw-frontend && npx -y @cyclonedx/cyclonedx-npm --output-file ../sbom-node.cdx.json); \
           else \
             echo "No package-lock.json found; skipping Node SBOM"; \
           fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Generate Node SBOM (CycloneDX NPM)
run: |
if [ -f pyproject.toml ]; then \
npx @appthreat/cdxgen -t python -o sbom-python.cdx.json; \
if [ -f package-lock.json ]; then \
npx -y @cyclonedx/cyclonedx-npm --output-file sbom-node.cdx.json; \
elif [ -f tldw-frontend/package-lock.json ]; then \
(cd tldw-frontend && npx -y @cyclonedx/cyclonedx-npm --output-file ../sbom-node.cdx.json); \
else \
echo "No package-lock.json found; skipping Node SBOM"; \
fi
- name: Generate Node SBOM (CycloneDX NPM)
run: |
set -euo pipefail
if [ -f package-lock.json ]; then \
npx -y @cyclonedx/cyclonedx-npm --output-file sbom-node.cdx.json; \
elif [ -f tldw-frontend/package-lock.json ]; then \
(cd tldw-frontend && npx -y @cyclonedx/cyclonedx-npm --output-file ../sbom-node.cdx.json); \
else \
echo "No package-lock.json found; skipping Node SBOM"; \
fi
🤖 Prompt for AI Agents
.github/workflows/sbom.yml lines 68-76: the Node SBOM run block omits strict
shell error handling so a failing npx can be ignored; add bash strict mode by
inserting "set -euo pipefail" as the first line of the run script so any command
failure (when package-lock.json exists) will stop the job, keeping the existing
conditional logic and subshells intact.


- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Resolve CycloneDX CLI digest
run: |
set -euo pipefail
ref="ghcr.io/cyclonedx/cyclonedx-cli:0.30.0"
echo "Resolving digest for ${ref}"
# Prefer buildx imagetools; fallback to manifest inspect if needed
if docker buildx imagetools inspect "$ref" >/dev/null 2>&1; then \
digest=$(docker buildx imagetools inspect "$ref" | awk '/^Digest:/ {print $2; exit}'); \
else \
digest=$(docker manifest inspect "$ref" | jq -r '.manifests[0].digest' || true); \
fi
if [ -z "${digest:-}" ] || ! echo "$digest" | grep -Eq '^sha256:[0-9a-f]{64}$'; then \
echo "Failed to resolve digest for $ref"; \
exit 1; \
fi
echo "CDX_CLI_DIGEST=$digest" >> "$GITHUB_ENV"
echo "Resolved digest: $digest"

- name: Generate SBOM (CycloneDX JSON)
uses: anchore/sbom-action@8e94d75ddd33f69f691467e42275782e4bfefe84 # v0.20.9
- name: Merge SBOMs (CycloneDX CLI)
run: |
if [ -f sbom-python.cdx.json ] && [ -f sbom-node.cdx.json ]; then \
docker run --rm -v "$PWD":/work -w /work ghcr.io/cyclonedx/cyclonedx-cli@${CDX_CLI_DIGEST} \
merge --input-files sbom-python.cdx.json sbom-node.cdx.json --output-file sbom.cdx.json; \
elif [ -f sbom-python.cdx.json ]; then \
cp sbom-python.cdx.json sbom.cdx.json; \
elif [ -f sbom-node.cdx.json ]; then \
cp sbom-node.cdx.json sbom.cdx.json; \
else \
echo "No SBOMs generated"; \
exit 1; \
fi

- name: Upload SBOM artifact
uses: actions/upload-artifact@v4
with:
path: .
format: cyclonedx-json
output-file: sbom.cdx.json
upload-artifact: true
artifact-name: sbom-cyclonedx

- name: Validate SBOM (CycloneDX CLI - pinned)
id: validate_cli_pinned
name: sbom-cyclonedx
path: sbom.cdx.json

- name: Validate SBOM (CycloneDX CLI - pinned digest)
if: ${{ hashFiles('sbom.cdx.json') != '' }}
continue-on-error: true
uses: docker://cyclonedx/cyclonedx-cli:0.30.0
with:
args: >-
validate --input-file sbom.cdx.json

- name: Validate SBOM (CycloneDX CLI - pinned fallback)
if: ${{ hashFiles('sbom.cdx.json') != '' && steps.validate_cli_pinned.outcome == 'failure' }}
uses: docker://cyclonedx/cyclonedx-cli:0.29.1
with:
args: >-
run: |
docker run --rm -v "$PWD":/work -w /work ghcr.io/cyclonedx/cyclonedx-cli@${CDX_CLI_DIGEST} \
validate --input-file sbom.cdx.json
96 changes: 96 additions & 0 deletions Docs/Design/IMPLEMENTATION_PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
## Implementation Plan — Browser Extension

This document tracks staged implementation with concrete success criteria and test notes.

---

## Stage 1: Connectivity & Auth
**Goal**: Establish server connectivity and both auth modes (API Key and JWT).

**Success Criteria**:
- Options page captures server URL and credentials; health check returns OK.
- Background proxy injects headers; tokens never exposed to content scripts.
- 401 triggers single‑flight refresh and one retry; no duplicate requests.

**Tests**:
- Unit: auth storage, header injection, refresh queue.
- Integration: health endpoint, login/logout, API key validation.
- Manual: revoke permission and re‑grant host permission flow.

**Status**: Not Started

---

## Stage 2: Chat & Models
**Goal**: Streaming chat via `/api/v1/chat/completions` with model selection.

**Success Criteria**:
- Models/providers fetched and rendered; selection persisted per session.
- Non‑stream and SSE stream both work; cancel stops network within ~200ms.
- Exact path strings (no 307 redirects observed in logs).

**Tests**:
- Unit: SSE parser, backoff, abort controller.
- Integration: stream across two models; cancel and resume.
- Manual: slow network simulation; ensure UI stays responsive.

**Status**: Not Started

---

## Stage 3: RAG & Media
**Goal**: RAG search UI and URL ingest with progress notifications.

**Success Criteria**:
- RAG `/api/v1/rag/search` returns results; snippets insert into chat context.
- URL ingest calls `/api/v1/media/process`; user sees progress and final status.
- Errors are actionable (permission, size limits, server busy).

**Tests**:
- Unit: request builders, snippet insertion.
- Integration: RAG queries; media process happy path and failure modes.
- Manual: ingest current tab URL; verify server reflects new media.

**Status**: Not Started

---

## Stage 4: Notes/Prompts & STT
**Goal**: Notes/Prompts basic flows and STT upload/transcribe.

**Success Criteria**:
- Notes: create/search; export works; selection‑to‑note from content script.
- Prompts: browse/import/export; insert chosen prompt into chat input.
- STT: upload short clip; transcript displayed; non‑supported formats fail clearly.

**Tests**:
- Unit: notes/prompts stores; MIME/type validation.
- Integration: `/api/v1/notes/*`, `/api/v1/prompts/*`, `/api/v1/audio/transcriptions`.
- Manual: 20s audio clip round‑trip; error message clarity for oversized files.

**Status**: Not Started

---

## Stage 5: TTS & Polish
**Goal**: TTS synthesis/playback and UX polish.

**Success Criteria**:
- Voices list loads from `/api/v1/audio/voices/catalog`; selection persisted.
- `/api/v1/audio/speech` returns audio; playback controls functional.
- Accessibility audit passes key checks; performance within budgets.

**Tests**:
- Unit: audio player controls and error states.
- Integration: voices catalog and synthesis endpoints.
- Manual: latency spot checks; keyboard navigation.

**Status**: Not Started

---

## Notes
- Centralize route constants and validate against OpenAPI at startup (warn on mismatch).
- Keep tokens in background memory; only persist refresh tokens if strictly necessary.
- Use optional host permissions for user‑configured origins (Chrome/Edge MV3).

Loading
Loading