File size: 20,700 Bytes
eb60b6b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
336e2c2
 
2f1e7ff
336e2c2
f21ebe0
 
 
 
 
 
 
 
 
 
336e2c2
eb60b6b
336e2c2
 
 
 
 
 
 
 
 
 
eb60b6b
336e2c2
 
 
eb60b6b
336e2c2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eb60b6b
336e2c2
eb60b6b
 
336e2c2
 
2f1e7ff
f21ebe0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
336e2c2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eb60b6b
336e2c2
 
 
5583f46
336e2c2
5583f46
 
 
336e2c2
 
 
 
 
 
eb60b6b
5583f46
 
 
 
 
 
 
 
 
 
 
 
 
09ca6cf
 
 
 
 
 
 
 
7135ba5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2f1e7ff
 
7135ba5
 
 
 
 
 
 
 
 
 
 
 
 
 
09ca6cf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2f1e7ff
 
09ca6cf
 
 
 
 
 
2f1e7ff
 
 
 
 
 
 
 
 
 
 
 
89e57b7
 
2f1e7ff
 
 
 
 
 
 
 
 
 
 
 
 
89e57b7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# Agent Deployment Guide for Hugging Face Space

This document serves as the guide and best practices for automated agents deploying and maintaining BrainAPI on Hugging Face Spaces.

## 1. Deployment Configuration

### Target Space
- **Profile:** `Leon4gr45`
- **Space:** `brain`
- **Full Identifier:** `Leon4gr45/brain`
- **Frontend Port:** `7860` (mandatory for Hugging Face Spaces)

### Deployment Method
- **Docker SDK** (`Dockerfile`)

### HF Token
- Always pass/read the HF access token from the environment (`HF_TOKEN` environment variable). Never hardcode secrets or token strings in repository files.

### Required Files
- `Dockerfile` (exposing nginx on port `7860`; uvicorn stays internal on port `8000`)
- `README.md` with Hugging Face YAML frontmatter:
  ```yaml
  ---
  title: BrainAPI
  sdk: docker
  app_port: 7860
  ---
  ```
- `.hfignore` to exclude `.git`, `.venv`, `node_modules`, and cache directories
- `Agent.md` (this file)

---

## 2. API Exposure and Documentation

### Mandatory Endpoints

- **`/health`**
  - Method: GET
  - Purpose: Returns HTTP 200 when the app is ready. Required for Hugging Face Space liveness.
  - Request: None
  - Response:
    ```json
    {
      "status": "ok",
      "service": "brainapi",
      "version": "2.19.0-dev"
    }
    ```

- **`/api-docs`**
  - Method: GET
  - Purpose: Redirects/Exposes full OpenAPI / Swagger documentation for all endpoints. Reachable at `https://Leon4gr45-brain.hf.space/api-docs`.
  - Response: HTTP 307 redirect to `/docs` or Swagger UI HTML page.

- **`/`**
  - Method: GET
  - Purpose: Redirects public root visits to `/console/`.
  - Response: HTTP 307 redirect to `/console/`.

---

## 3. Deployment Workflow & Ongoing Best Practices

1. **Pre-flight Check:**
   Clean up non-project or stale files in the target Hugging Face Space using `huggingface_hub` Python API.

2. **Deploy Command:**
   ```bash
   python deploy/hf_space.py stage --output /tmp/brainapi-hf-source
   # Inspect/build the staged tree before uploading that same Git revision.
   python deploy/hf_space.py upload --revision HEAD
   ```

   This stages the complete committed Git tree, checks every required Docker
   input, and verifies the uploaded Space files against the staged content.
   Run it from the BrainAPI checkout with `huggingface_hub` installed and
   `HF_TOKEN` set through secure environment settings. Do not upload a manually
   selected list of changed files. The readiness wrapper must remain in the
   Space repository alongside `scripts/preload_ollama_models.sh`.

3. **Log Monitoring:**
   - **Build Logs (SSE):**
     ```bash
     curl -N -H "Authorization: Bearer $HF_TOKEN" "https://huggingface.co/api/spaces/Leon4gr45/brain/logs/build"
     ```
   - **Run Logs (SSE):**
     ```bash
     curl -N -H "Authorization: Bearer $HF_TOKEN" "https://huggingface.co/api/spaces/Leon4gr45/brain/logs/run"
     ```

4. **Iterative Debugging:**
   Inspect build and run logs for missing dependencies, port binding issues, or startup exceptions. Modify codebase accordingly, redeploy, and monitor until the Space reaches `RUNNING` status and responds to `/health` and `/api-docs`.

### Functional Endpoints

### /retrieve/context
- **Method:** POST
- **Purpose:** Retrieve an entity's contextual information based on a given text, generating triples and passages.
- **Authentication:** Requires `BrainPAT` header or Bearer token verified by the central AuthService.
- **Request (JSON):**
  - `text` (str, required): The text to search context for.
  - `brain_id` (str, optional, default: `"default"`): The brain/workspace identifier to query.
  - `historical_limit` (int, optional, default: `10`)
  - `max_facts` (int, optional, default: `40`, min: `0`)
  - `max_passages` (int, optional, default: `8`)
  - `apply_fact_filter` (bool, optional, default: `true`)
  - `use_ppr` (bool, optional, default: `true`)
  - `sufficiency_retry` (bool, optional, default: `false`)
  - `profile_stages` (bool, optional, default: `false`)
  - `cross_event_bridges` (int, optional, default: `3`, min: `0`)
  ```json
  {
    "text": "Identify memory leaks in Python",
    "brain_id": "default",
    "historical_limit": 10,
    "max_facts": 40,
    "max_passages": 8,
    "apply_fact_filter": true,
    "use_ppr": true,
    "sufficiency_retry": false,
    "profile_stages": false,
    "cross_event_bridges": 3
  }
  ```
- **Response (JSON):**
  ```json
  {
    "text_context": "Found 3 passages and 10 triples related to the query...",
    "triples": [
      {
        "identified_entity": "memory_leak",
        "triple": [
          {"id": "python", "label": "Language", "properties": {"name": "Python"}},
          {"id": "causes", "type": "CAUSES", "properties": {}},
          {"id": "memory_leak", "label": "Issue", "properties": {"name": "Memory Leak"}}
        ],
        "source_chunk_ids": ["chunk-123"]
      }
    ],
    "historical_context": ["Previous discussions about memory profiling..."],
    "source_passages": ["Python's garbage collector sometimes misses reference cycles..."],
    "graph_session_ids": ["sess-456"],
    "temporal_conflicts": [],
    "paths": [],
    "topics": [{"topic": "performance", "weight": 0.8}],
    "stage_timings": {"retrieval": 0.15, "formatting": 0.02}
  }
  ```

### /retrieve/search
- **Method:** POST (Canonical) / GET (Compatibility)
- **Purpose:** Execute a ranked search across passages, entities, events, communities, and plugins with optional re-ranking.
- **Authentication:** Requires `BrainPAT` header or Bearer token verified by the central AuthService.
- **Request (POST JSON or GET Query Params):**
  - `query` (str, required): The search query.
  - `brain_id` (str, optional, default: `"default"`): The brain identifier to query.
  - `k` (int, optional, default: `10`, range: `1-200`): Number of hits to return.
  - `channels` (List[str], optional, default: `["passages"]`): Channels to search. Allowed channels include `passages`, `entities`, `events`, `communities`, and/or `plugin:<name>`.
  - `node_labels` (List[str], optional, default: `null`): Node labels to filter the entities channel.
  - `community_labels` (List[str], optional, default: `null`): Hub labels for the communities channel.
  - `expand` (str, optional, default: `"none"`): Allowed values: `"none"`, `"neighbors"`. Optional 1-hop expansion from graph channel seeds.
  - `fusion` (str, optional, default: `null`): Fusion override. Allowed values: `"rrf"`, `"cc"`.
  - `fusion_alpha` (float, optional, default: `null`, range: `0.0-1.0`)
  - `rerank` (str, optional, default: `null`): `none` or `plugin:<name>`. Unknown plugin names return 400.
  - `mode` (str, optional, default: `"default"`): Allowed values: `"default"`, `"catalog"`.
  - `profile_stages` (bool, optional, default: `false`)
  - `extras` (Dict[str, str], optional, default: `null`)
  - `target` (str, optional, default: `null`): Optional USER uuid or id for query-gated rerank of retrieved hits.
  ```json
  {
    "query": "hello world",
    "brain_id": "default",
    "k": 10,
    "channels": ["passages", "entities"],
    "node_labels": ["Document", "Author"],
    "community_labels": ["Tech"],
    "expand": "none",
    "fusion": "rrf",
    "fusion_alpha": 0.5,
    "rerank": "plugin:cohere",
    "mode": "default",
    "profile_stages": false,
    "extras": {},
    "target": "user-123"
  }
  ```
- **Response (JSON):**
  ```json
  {
    "hits": [
      {
        "id": "hit-789",
        "channel": "passages",
        "score": 0.95,
        "scores": {"dense": 0.95, "bm25": 4.2, "rrf": 0.033},
        "snippet": "Hello World example in Python",
        "extras": {"author": "Jane Doe"}
      }
    ],
    "stage_timings": {"search": 0.08, "rerank": 0.12},
    "channel_lists": {"passages": ["hit-789"]},
    "facets": {"author": {"Jane Doe": 1}},
    "node_ids": ["node-456"]
  }
  ```
## HF CPU embedding contract

Use `embeddinggemma2-text-v1`: Ollama `embeddinggemma-2:270m`, 8192-token maximum,
768 native dimensions -> first 512 -> L2 normalization. All five primary pgvector
stores must be `vector(512)`. Never mix model identities even at equal dimensions;
index/profile mismatches must fail without dropping or reusing old vectors.
The baseline image preloads only Gemma; chat and reranking remain optional.
See `deploy/env.hf.cpu.example` and `deploy/README.ollama.md`. Before production,
commit and stage the exact source, build that staged tree, and run
`/app/entrypoint.sh --qualify` inside the local image (it runs the qualification
script with the service configuration). Do not upload a
production deployment until both the full build and real qualification pass.

## 4. Tricks and Ongoing Deployment Best Practices

### Custom Deployment Script
- Deployments to Hugging Face Spaces must use the custom `deploy/hf_space.py` complete-tree helper script rather than a plain `hf upload`. Use `python deploy/hf_space.py stage --revision HEAD --output /tmp/brainapi-hf-source` followed by `python deploy/hf_space.py upload --revision HEAD` to ensure the staged tree correctly matches the committed revision.

### Environment Variable Normalization
- String environment variables mapped into configuration classes (e.g., `provider`, `model`, `profile` in `src/config.py`) must be explicitly normalized early using `.strip()` and `.lower()` at the boundary to prevent invisible whitespace or case mismatch validation errors.
- When logging environment variable diagnostics in shell scripts like `entrypoint.sh`, place `echo` and `printf` statements after the fallback default evaluation variables are evaluated (e.g., `export VAR="${VAR:-default}"`) to ensure the effective runtime configurations are captured.

### Docker and Hub Constraints
- If a Hugging Face Space configured with the Docker SDK reports 'missing an app file', it means the `Dockerfile` is missing from the remote repository and must be explicitly uploaded alongside the `README.md` to trigger the build.
- The `deploy/` directory must not be excluded in `.dockerignore` so that Supervisord and Nginx configurations can be copied during Docker image builds.
- `.dockerignore` must exclude `node_modules/`, `console/node_modules/`, and `tui/node_modules/` to prevent copying local node dependencies into Docker build stages.
- The `README.md` requires Hugging Face YAML frontmatter at the very top of the file including `title: BrainAPI`, `emoji`, `colorFrom`, `colorTo`, `sdk: docker`, `app_port: 7860`, and `pinned` configurations to satisfy constraints.
- Do not hardcode Hugging Face access token strings in repository files like `Agent.md`, as HF Hub security filters reject commits containing raw tokens.

### Docker Startup & Service Coordination
- In Supervisord process definitions, the Celery worker application module is `src.workers.app:ingestion_app` and the MCP ASGI server module is `src.services.mcp.app:app`.
- For Hugging Face Spaces compatibility, the API is configured in `deploy/supervisord.conf` under `[program:brainapi-api]` to run Uvicorn on `0.0.0.0` port `7860` natively (or handled by an Nginx reverse proxy on 7860 to internal 8000).
- Setting `serverSelectionTimeoutMS` (e.g. 2000ms) on `PyMongoClient` prevents 30-second blocking timeouts when MongoDB is offline during startup.
- The PostgreSQL extension `vector` is pre-created in `template1` as superuser `postgres` in `entrypoint.sh` so that newly initialized workspace databases automatically inherit `pgvector` without requiring `SUPERUSER` privileges for user `brainapi`.
- In all-in-one container deployments, Supervisord orchestrates local PostgreSQL (with `pgvector`), Redis, FastAPI API, MCP server, Celery worker, and Nginx, using persistent secrets stored in `/data/brainapi/internal-secrets.env`.
- In standalone deployment container environments, setting `PIPELINE_MODE=lightweight` and `EMBEDDINGS_PROVIDER=mock` or `fastembed` avoids hard runtime dependencies on external LLM services or Ollama instances.

### Security
- `SYSTEM_PAT` must be provided as an environment variable or Hugging Face Space Secret and never hardcoded in repository files or test scripts.
- Public UI and documentation endpoints (`/`, `/console`, `/docs`, `/redoc`, `/health`, `/openapi.json`, `/api-docs`, `/favicon.ico`) must be excluded from `BrainPATMiddleware` and `BrainMiddleware` authentication checks. `GET /` redirects to `/console/`.

### Testing and Documentation Rules
- Functional API endpoints (e.g., `/retrieve/context`, `/retrieve/search`) must be explicitly documented in `Agent.md` under the `### Functional Endpoints` section, including their Method, Path, Purpose, Request, and Response structures.
- API endpoints documented in `Agent.md` should strictly match the actual implementation (route decorators and Pydantic models). The canonical HTTP method (e.g., POST) should be presented as the primary interface, without modifying API behavior just to match docs.
- The local test suite must be executed using `PYTHONPATH=tests poetry run pytest` to resolve import errors for test helper modules.
- `Config` in `src/config.py` conditionally instantiates database sub-configurations (`mongo`, `milvus`, `neo4j`, `postgresql`) based on `DATA_DB`, `VECTOR_DB`, and `GRAPH_DB` environment variables.

## 4. Tricks and Ongoing Deployment Best Practices

### Custom Deployment Script
- Deployments to Hugging Face Spaces must use the custom `deploy/hf_space.py` complete-tree helper script rather than a plain `hf upload`. Use `python deploy/hf_space.py stage --revision HEAD --output /tmp/brainapi-hf-source` followed by `python deploy/hf_space.py upload --revision HEAD` to ensure the staged tree correctly matches the committed revision.

### Environment Variable Normalization
- String environment variables mapped into configuration classes (e.g., `provider`, `model`, `profile` in `src/config.py`) must be explicitly normalized early using `.strip()` and `.lower()` at the boundary to prevent invisible whitespace or case mismatch validation errors.
- When logging environment variable diagnostics in shell scripts like `entrypoint.sh`, place `echo` and `printf` statements after the fallback default evaluation variables are evaluated (e.g., `export VAR="${VAR:-default}"`) to ensure the effective runtime configurations are captured.

### Docker and Hub Constraints
- If a Hugging Face Space configured with the Docker SDK reports 'missing an app file', it means the `Dockerfile` is missing from the remote repository and must be explicitly uploaded alongside the `README.md` to trigger the build.
- The `deploy/` directory must not be excluded in `.dockerignore` so that Supervisord and Nginx configurations can be copied during Docker image builds.
- `.dockerignore` must exclude `node_modules/`, `console/node_modules/`, and `tui/node_modules/` to prevent copying local node dependencies into Docker build stages.
- The `README.md` requires Hugging Face YAML frontmatter at the very top of the file including `title: BrainAPI`, `emoji`, `colorFrom`, `colorTo`, `sdk: docker`, `app_port: 7860`, and `pinned` configurations to satisfy constraints.
- Do not hardcode Hugging Face access token strings in repository files like `Agent.md`, as HF Hub security filters reject commits containing raw tokens.

### Docker Startup & Service Coordination
- In Supervisord process definitions, the Celery worker application module is `src.workers.app:ingestion_app` and the MCP ASGI server module is `src.services.mcp.app:app`.
- For Hugging Face Spaces compatibility, the API is configured in `deploy/supervisord.conf` under `[program:brainapi-api]` to run Uvicorn on `0.0.0.0` port `7860` natively (or handled by an Nginx reverse proxy on 7860 to internal 8000).
- Setting `serverSelectionTimeoutMS` (e.g. 2000ms) on `PyMongoClient` prevents 30-second blocking timeouts when MongoDB is offline during startup.
- The PostgreSQL extension `vector` is pre-created in `template1` as superuser `postgres` in `entrypoint.sh` so that newly initialized workspace databases automatically inherit `pgvector` without requiring `SUPERUSER` privileges for user `brainapi`.
- In all-in-one container deployments, Supervisord orchestrates local PostgreSQL (with `pgvector`), Redis, FastAPI API, MCP server, Celery worker, and Nginx, using persistent secrets stored in `/data/brainapi/internal-secrets.env`.
- In standalone deployment container environments, setting `PIPELINE_MODE=lightweight` and `EMBEDDINGS_PROVIDER=mock` or `fastembed` avoids hard runtime dependencies on external LLM services or Ollama instances.

### Security
- `SYSTEM_PAT` must be provided as an environment variable or Hugging Face Space Secret and never hardcoded in repository files or test scripts.
- Public UI and documentation endpoints (`/`, `/console`, `/docs`, `/redoc`, `/health`, `/openapi.json`, `/api-docs`, `/favicon.ico`) must be excluded from `BrainPATMiddleware` and `BrainMiddleware` authentication checks. `GET /` redirects to `/console/`.

### Testing and Documentation Rules
- Functional API endpoints (e.g., `/retrieve/context`, `/retrieve/search`) must be explicitly documented in `Agent.md` under the `### Functional Endpoints` section, including their Method, Path, Purpose, Request, and Response structures.
- API endpoints documented in `Agent.md` should strictly match the actual implementation (route decorators and Pydantic models). The canonical HTTP method (e.g., POST) should be presented as the primary interface, without modifying API behavior just to match docs.
- The local test suite must be executed using `PYTHONPATH=tests poetry run pytest` to resolve import errors for test helper modules.
- `Config` in `src/config.py` conditionally instantiates database sub-configurations (`mongo`, `milvus`, `neo4j`, `postgresql`) based on `DATA_DB`, `VECTOR_DB`, and `GRAPH_DB` environment variables.

## Credential model

`SYSTEM_PAT` is the single administrator credential across HTTP, console, and MCP.
The deprecated `BRAINPAT_TOKEN` may only alias that same value; a conflict fails
startup. Brains/workspaces do not generate credentials. Issue named access tokens
via `/system/access-tokens`, copy the plaintext once, and revoke independently.
Browser login uses `/auth/session` and `/auth/me`; a system session has no selected
brain (`brain_id=null`). The console stores no submitted access credential.
See `docs/security/credentials.md` for legacy migration and exposed-token rotation.

`/health` reports durability. Ephemeral staging requires explicit
`ALLOW_EPHEMERAL_STORAGE=true` and remains degraded / production NO-GO unless the
operator explicitly accepts the checkpointed-production policy documented below.

## GitHub Brain content recovery

Read [content checkpoint/recovery instructions](docs/content-backup.md) before
working on persistence. HF startup restores validated logical checkpoints from
`JsonLord/nodepad-brain-backup:main` using the separate `GITHUB_PAT` Space secret,
before workspace bootstrap and serving. Never back up auth registries/tokens,
Redis, internal secrets, or PGDATA; never force push or overwrite nonempty local
state of unknown lineage. API/MCP check the current container's restore gate.
Configure the documented `BRAIN_BACKUP_*` variables; keep async checkpoint RPO and
ephemeral health limitations explicit. No automatic deployment. The disposable
round-trip gate is `scripts/qualify_content_backup.py`; never point it at real
Brain databases. Auth tokens are separately reissued after ephemeral recovery.

For planned HF restarts, quiesce writers and verify a completed remote checkpoint
before replacement. HF replacement startup can overlap the old container's final
shutdown push; do not rely on that final push as a restore barrier. Compare the
restored commit with the intended checkpoint before resuming writes. See the
[live qualification and observed limitations](docs/content-backup-live-qualification.md).

The administrator maintenance API now enforces that sequence: quiesce/checkpoint,
record remotely verified SHA, rebuild, verify replacement restored/current SHA and
retrieval while still held, then explicitly resume. See `/system/backup/status`.
A manifest handoff hold survives replacement. Startup remote-head advances fail
closed before serving. Never bypass a hold or lineage failure to force readiness.

`BRAIN_BACKUP_MAX_RPO_SECONDS` defaults to the checkpoint interval (300).
`ALLOW_CHECKPOINTED_PRODUCTION=false` preserves ephemeral production NO-GO. Only
an explicit operator opt-in can accept checkpointed production, and only while
all remote/RPO/auth/database/embedding/access-log checks pass. Report the policy,
observed checkpoint age, and `zero_loss_durable=false` without implying zero loss.