diff --git a/projects/scirium/01-product-model.md b/projects/scirium/01-product-model.md index 3cc517c..23dd45c 100644 --- a/projects/scirium/01-product-model.md +++ b/projects/scirium/01-product-model.md @@ -1,4 +1,4 @@ -# Wall-O: Product Model and Data Architecture +# Scirium: Product Model and Data Architecture Status: PLANNED First client: Wall Orthodontics @@ -98,7 +98,7 @@ One row per AI persona. Bound to exactly one channel. | agent_id | UUID | PK | Canonical identifier. | | tenant_id | UUID | FK to tenants.tenant_id, NOT NULL | Multi-tenant isolation. | | channel_id | UUID | FK to channels.channel_id, UNIQUE, NOT NULL | One agent per channel. | -| name | TEXT | NOT NULL | Agent display name, for example "Wallo Billing". | +| name | TEXT | NOT NULL | Agent display name, for example "Scirium Billing". | | system_prompt | TEXT | NOT NULL | Domain-tuned persona and instructions. | | kb_scope_id | UUID | FK to kb_scopes.kb_scope_id, NULL | What this agent may retrieve. | | model_provider | TEXT | NOT NULL DEFAULT 'admin-ai' | LLM gateway. | @@ -254,15 +254,15 @@ A staff member either @mentions the agent bot in a channel, or DMs the bot direc Channel mentions are captured by an outgoing webhook integration configured on the channel with trigger word equal to the bot username. Rocket.Chat POSTs to: ``` -POST https://orchestrator.wall-o./api/v1/webhook/rocketchat/{tenant_slug} +POST https://orchestrator.scirium./api/v1/webhook/rocketchat/{tenant_slug} ``` Headers: | Header | Value | |---|---| -| X-WallO-Signature | Hex HMAC-SHA256 of the raw request body, keyed by the tenant webhook secret. | -| X-WallO-Timestamp | Unix seconds. Reject if skew is greater than 300 seconds. | +| X-Scirium-Signature | Hex HMAC-SHA256 of the raw request body, keyed by the tenant webhook secret. | +| X-Scirium-Timestamp | Unix seconds. Reject if skew is greater than 300 seconds. | | Content-Type | application/json | Payload (Rocket.Chat outgoing webhook shape): @@ -275,8 +275,8 @@ Payload (Rocket.Chat outgoing webhook shape): "timestamp": "2026-08-15T12:00:00.000Z", "user_id": "", "user_name": "jane.doe", - "text": "@wallo-billing How do I submit a PTO request?", - "trigger_word": "@wallo-billing", + "text": "@scirium-billing How do I submit a PTO request?", + "trigger_word": "@scirium-billing", "bot": false } ``` @@ -289,7 +289,7 @@ DM capture does not use this webhook. Rocket.Chat outgoing webhooks do not fire Resolution order, all in one request context: -1. Authenticate: verify `X-WallO-Signature` against the tenant webhook secret looked up by `tenant_slug`. +1. Authenticate: verify `X-Scirium-Signature` against the tenant webhook secret looked up by `tenant_slug`. 2. Idempotency: derive `rocket_chat_message_id` from a hash of (channel_id, user_id, timestamp, text). If a `messages` row already exists with that id, return HTTP 200 immediately and do nothing. This deduplicates webhook retries. 3. Resolve channel: `SELECT * FROM channels WHERE tenant_id = ? AND rocket_chat_room_id = ?`, with a fallback match on `rocket_chat_room_name`/`slug`. 4. Resolve agent: read `channel.agent_id`, then `SELECT * FROM agents WHERE agent_id = ?`. @@ -404,7 +404,7 @@ Steps 1 through 3 are idempotent API calls driven by an onboarding form in the o ## 7. Agent Identity and Response Citations -Identity: the bot posts with its own username and avatar (set at provisioning). Every answer is attributed to the bot user, never to a human, so staff can distinguish agent answers from colleague messages. The `system_prompt` instructs the agent to introduce itself as the channel's assistant (for example "I am the Wall-O assistant for Employee Resources") and to stay inside the domain. +Identity: the bot posts with its own username and avatar (set at provisioning). Every answer is attributed to the bot user, never to a human, so staff can distinguish agent answers from colleague messages. The `system_prompt` instructs the agent to introduce itself as the channel's assistant (for example "I am the Scirium assistant for Employee Resources") and to stay inside the domain. Citations: retrieved chunks carry provenance in `metadata` (document title, section heading, page). During prompt assembly each chunk is labeled `[1]`, `[2]`, and so on. The orchestrator renders the final answer with inline `[n]` markers and appends a "Sources" footer listing each cited document title and a link (Microsoft Graph sharing link, or a Rocket.Chat file link). The full provenance (document_id, chunk_id, title, snippet, url) is stored in `messages.citations` as JSONB for audit and re-render. If the answer cites nothing, no footer is emitted. diff --git a/projects/scirium/02-m365-connector.md b/projects/scirium/02-m365-connector.md index 0311506..47e43aa 100644 --- a/projects/scirium/02-m365-connector.md +++ b/projects/scirium/02-m365-connector.md @@ -1,7 +1,7 @@ -# Wall-O: M365 Connector + Retrieval Architecture +# Scirium: M365 Connector + Retrieval Architecture Status: DESIGN (internal technical architecture) -Owner: Wall-O build team +Owner: Scirium build team Scope: Internal staff knowledge only. Employee handbook, policies, procedures, billing questions. Excluded: Patient records, PHI, any HIPAA-regulated data. This connector MUST NOT be pointed at clinical or patient data sources. @@ -37,7 +37,7 @@ This lets one app identity serve every practice tenant. Each practice admin cons ### 1.2 Permission strategy: Sites.Selected over Sites.Read.All -Wall-O reads documents, never writes. Least privilege is achieved with the `Sites.Selected` application permission rather than the broad `Sites.Read.All`. +Scirium reads documents, never writes. Least privilege is achieved with the `Sites.Selected` application permission rather than the broad `Sites.Read.All`. | Permission | Type | Scope | Why accepted / rejected | |---|---|---|---| @@ -46,7 +46,7 @@ Wall-O reads documents, never writes. Least privilege is achieved with the `Site | Files.Read.All | Application | Every file in every drive | REJECTED. Superseded by Sites.Selected for site-scoped read. | | User.Read.All | Application | Read directory user profiles | OPTIONAL. Needed only to resolve author display names from OneDrive drive owner IDs. Not required for retrieval. | -`Sites.Selected` supports site-level roles: `read`, `write`, `fullcontrol`, `manage`. Wall-O requests `read` only. The grant is issued per site collection via: +`Sites.Selected` supports site-level roles: `read`, `write`, `fullcontrol`, `manage`. Scirium requests `read` only. The grant is issued per site collection via: ``` POST https://graph.microsoft.com/v1.0/sites/{site-id}/permissions @@ -55,12 +55,12 @@ Content-Type: application/json { "roles": ["read"], "grantedToIdentities": [ - { "application": { "id": "{wall-o-app-client-id}", "displayName": "Wall-O" } } + { "application": { "id": "{scirium-app-client-id}", "displayName": "Scirium" } } ] } ``` -This request is made by the orchestrator using the app's own token for the tenant. Because the app already holds `Sites.Selected`, it can grant itself `read` on a specific site once a practice admin has approved the site in onboarding. A stricter variant has a practice global admin run the grant via Graph Explorer so the app never self-grants. Wall-O uses the admin-driven variant: the grant is issued during onboarding by the practice admin (or by the orchestrator on a one-time admin-approved site list), not by the app unprompted. +This request is made by the orchestrator using the app's own token for the tenant. Because the app already holds `Sites.Selected`, it can grant itself `read` on a specific site once a practice admin has approved the site in onboarding. A stricter variant has a practice global admin run the grant via Graph Explorer so the app never self-grants. Scirium uses the admin-driven variant: the grant is issued during onboarding by the practice admin (or by the orchestrator on a one-time admin-approved site list), not by the app unprompted. ### 1.3 Client credentials grant @@ -91,7 +91,7 @@ Notes: - `{tenant_id}` is the consuming practice's directory (tenant) ID, captured at consent time. It is NOT `common` or `organizations`: client credentials has no user to derive a tenant from, so the target tenant must be explicit. - `.default` expands to the union of the application permissions already consented for that tenant. It is not a literal scope name. - Response contains `access_token` and `expires_in`. Graph client credentials tokens are typically valid for about 60 minutes; treat `expires_in` as authoritative, never hardcode the TTL. -- Credential material: prefer an X.509 client certificate (assertion) over a client secret. A secret is acceptable for MVP but must be rotated before its maximum lifetime (24 months). Secrets live in Vaultwarden under the Wall-O project; only the encrypted reference enters Postgres or config. +- Credential material: prefer an X.509 client certificate (assertion) over a client secret. A secret is acceptable for MVP but must be rotated before its maximum lifetime (24 months). Secrets live in Vaultwarden under the Scirium project; only the encrypted reference enters Postgres or config. ### 1.4 Admin consent URL construction @@ -99,18 +99,18 @@ Each practice admin must consent the app into their tenant before the first craw ``` https://login.microsoftonline.com/{tenant_id}/v2.0/adminconsent - ?client_id={wall-o-app-client-id} + ?client_id={scirium-app-client-id} &scope=https://graph.microsoft.com/.default &redirect_uri={configured-redirect-uri} ``` - `{tenant_id}`: the practice's directory ID, or `organizations` to let the signing admin's tenant be used automatically. -- `redirect_uri`: a registered reply URL on the app. Wall-O registers a no-op callback (e.g. `https://wall-o.itpropartner.com/entra/callback`) that returns a 200 and logs the consent result. +- `redirect_uri`: a registered reply URL on the app. Scirium registers a no-op callback (e.g. `https://scirium.itpropartner.com/entra/callback`) that returns a 200 and logs the consent result. - The scope string is URL-encoded `.default` (i.e. `https%3A%2F%2Fgraph.microsoft.com%2F.default`). Onboarding flow per practice: -1. Practice admin clicks the consent URL (delivered by the Wall-O onboarding UI or support). +1. Practice admin clicks the consent URL (delivered by the Scirium onboarding UI or support). 2. Admin authenticates and approves the `Sites.Selected` application permission. 3. On success Entra redirects to the callback. The orchestrator records `tenant_id`, consent timestamp, and the admin's identity. 4. The site-level `read` grant (1.2) is then applied to the specific site collections mapped to that practice's channels. @@ -138,7 +138,7 @@ Lifecycle rules: - On `401 Unauthorized` with `InvalidAuthenticationToken`, or `403` with a consent/scope error, the connector retries once with a freshly issued token. A second failure escalates. - Error code mapping: - `AADSTS700016` (application not found in directory) or `AADSTS7000112` (invalid client) means the app is not consented in that tenant: mark `consent_revoked`, alert practice admin. - - `AADSTS700082` or expired secret errors mean the secret is expired/rotated: mark `secret_expired`, page the Wall-O operator. + - `AADSTS700082` or expired secret errors mean the secret is expired/rotated: mark `secret_expired`, page the Scirium operator. - Graph throttling `429` is not an auth failure: honor `Retry-After` and back off; do not flag the tenant. - Token issuance and refresh are serialized per tenant (single-flight lock) so concurrent sync workers do not stampede the token endpoint. - Tokens are never logged or returned by any API. Logging redacts the `Authorization` header. @@ -244,7 +244,7 @@ Content-Type: application/json { "changeType": "updated", - "notificationUrl": "https://wall-o.itpropartner.com/entra/notifications", + "notificationUrl": "https://scirium.itpropartner.com/entra/notifications", "resource": "/sites/{site-id}/drive/root", "expirationDateTime": "2026-08-18T18:00:00Z", "clientState": "tenant_{tenant_id}" @@ -421,12 +421,12 @@ The combination means authorization is enforced at both ingestion (Graph site gr | Backup to Wasabi | Inherits existing Postgres S3 backup | Separate snapshot/export | Separate persistence | | Metadata + filters | Native SQL join with tenant/channel tables | Payload filters (separate model) | Metadata filter, less mature | -Rationale: ITPP already runs Postgres with backup to Wasabi S3, on self-hosted netcup servers. Wall-O's scale is moderate: a practice's internal staff knowledge base is hundreds to low thousands of documents, tens of thousands to low millions of chunks across all tenants. pgvector handles this comfortably with an HNSW index, adds zero new stateful services, keeps vectors and tenancy metadata in one transactional database (atomic upsert, consistent deletes), and inherits the existing backup and HA story. Qdrant would be justified only at very large scale or if vectors needed independent scaling from metadata; Chroma's single-node embedded design is the wrong fit for a multi-tenant production service. +Rationale: ITPP already runs Postgres with backup to Wasabi S3, on self-hosted netcup servers. Scirium's scale is moderate: a practice's internal staff knowledge base is hundreds to low thousands of documents, tens of thousands to low millions of chunks across all tenants. pgvector handles this comfortably with an HNSW index, adds zero new stateful services, keeps vectors and tenancy metadata in one transactional database (atomic upsert, consistent deletes), and inherits the existing backup and HA story. Qdrant would be justified only at very large scale or if vectors needed independent scaling from metadata; Chroma's single-node embedded design is the wrong fit for a multi-tenant production service. Implementation notes: - Extension: `CREATE EXTENSION vector;` (pgvector >= 0.5.0 for HNSW; newer for larger dimension support). -- Index: HNSW on the embedding column. Because queries are namespace-scoped, use a filtered/partial strategy: either a composite approach (HNSW per namespace table via partitioning) or a single HNSW with the namespace filter applied post-recall. At Wall-O scale, a single HNSW index plus a namespace equality filter in the WHERE clause is sufficient and simplest. +- Index: HNSW on the embedding column. Because queries are namespace-scoped, use a filtered/partial strategy: either a composite approach (HNSW per namespace table via partitioning) or a single HNSW with the namespace filter applied post-recall. At Scirium scale, a single HNSW index plus a namespace equality filter in the WHERE clause is sufficient and simplest. - Dimension: 1024 (see 5.2), well within pgvector's limits. - Distance: cosine (`<=>`) with L2-normalized vectors. - Chunk text and metadata live in the same table so retrieval returns citations in one query with no join to an object store for the common path. Wasabi S3 remains the archive for raw downloaded files and full-text backups, not the retrieval hot path. @@ -440,7 +440,7 @@ Implementation notes: | BAAI/bge-large-en-v1.5 | 1024 | Self-hosted on app server | FALLBACK. Zero external dependency and free, but adds model serving burden and slightly weaker than text-embedding-3-large on this task. | | bge-m3 | 1024 | Self-hosted | Only if multilingual staff content appears; out of scope for English-only Wall Orthodontics. | -Rationale: Wall-O routes LLM calls through admin-ai (DeepSeek V4 Pro primary) already, so embeddings through the same LiteLLM gateway are the lowest-operational-overhead choice and keep spend attributable to the Wall-O virtual key. text-embedding-3-large with Matryoshka truncation to 1024 dimensions gives near-full quality at a quarter of the storage and index cost. The model is pinned and documented so index and query always use identical dimensionality and normalization; changing models requires a documented full re-embed of every namespace (a versioned embedding-model field on the chunk table gates this). +Rationale: Scirium routes LLM calls through admin-ai (DeepSeek V4 Pro primary) already, so embeddings through the same LiteLLM gateway are the lowest-operational-overhead choice and keep spend attributable to the Scirium virtual key. text-embedding-3-large with Matryoshka truncation to 1024 dimensions gives near-full quality at a quarter of the storage and index cost. The model is pinned and documented so index and query always use identical dimensionality and normalization; changing models requires a documented full re-embed of every namespace (a versioned embedding-model field on the chunk table gates this). --- @@ -450,4 +450,4 @@ Rationale: Wall-O routes LLM calls through admin-ai (DeepSeek V4 Pro primary) al - `Sites.Selected` read grants only; no tenant-wide read permission in production. - Namespace (tenant + kb_scope) is a mandatory equality filter on every retrieval and every Graph fallback search. - Client secret (or certificate) in Vaultwarden; tokens encrypted at rest in Postgres; nothing in logs. -- No em dashes, en dashes, or double hyphens in this document or any Wall-O docs. +- No em dashes, en dashes, or double hyphens in this document or any Scirium docs. diff --git a/projects/scirium/03-deployment-white-label.md b/projects/scirium/03-deployment-white-label.md index 80a7768..c8073b2 100644 --- a/projects/scirium/03-deployment-white-label.md +++ b/projects/scirium/03-deployment-white-label.md @@ -1,4 +1,4 @@ -# Wall-O: Deployment, White-Label, and Phase 0 Build Plan +# Scirium: Deployment, White-Label, and Phase 0 Build Plan Scope: multi-tenant internal staff knowledge-base chat. Rocket.Chat is chat transport only (one workspace per tenant). The orchestrator is a multi-tenant FastAPI service that owns tenancy, agents, kb_scope, the M365 connector, retrieval, and LLM. Strictly internal staff knowledge. No patient records, no PHI. @@ -10,13 +10,13 @@ Canonical entities: tenant_id (a practice), channel_id (a knowledge domain with | Component | Host | Port | Scope | Scales per tenant | |---|---|---|---|---| -| Caddy reverse proxy | wall-o host | 80 / 443 | shared | single process, per-tenant site blocks | -| Orchestrator (FastAPI, ASGI via uvicorn worker) | wall-o host | 127.0.0.1:8000 | shared | 1 instance; add workers or a second host behind a load balancer | -| Orchestrator DB (Postgres + pgvector) | wall-o host | 127.0.0.1:5432 | shared | 1 primary; promote to a replica for read scale | -| Rocket.Chat workspace (tenant N) | wall-o host | 127.0.0.1:3010N | per tenant | 1 Docker Compose stack per tenant, no shared state | -| MongoDB (tenant N, Rocket.Chat native store) | wall-o host | 127.0.0.1:2710N (loopback only) | per tenant | 1 Mongo per tenant, isolated volume | -| Branding assets (logo, favicon, custom CSS, PWA shell) | wall-o host | /var/www/wall-o/ | per tenant | static files, chmod 644, no process | -| M365 connector (orchestrator module) | wall-o host | n/a (in-process) | shared | horizontal with the orchestrator | +| Caddy reverse proxy | scirium host | 80 / 443 | shared | single process, per-tenant site blocks | +| Orchestrator (FastAPI, ASGI via uvicorn worker) | scirium host | 127.0.0.1:8000 | shared | 1 instance; add workers or a second host behind a load balancer | +| Orchestrator DB (Postgres + pgvector) | scirium host | 127.0.0.1:5432 | shared | 1 primary; promote to a replica for read scale | +| Rocket.Chat workspace (tenant N) | scirium host | 127.0.0.1:3010N | per tenant | 1 Docker Compose stack per tenant, no shared state | +| MongoDB (tenant N, Rocket.Chat native store) | scirium host | 127.0.0.1:2710N (loopback only) | per tenant | 1 Mongo per tenant, isolated volume | +| Branding assets (logo, favicon, custom CSS, PWA shell) | scirium host | /var/www/scirium/ | per tenant | static files, chmod 644, no process | +| M365 connector (orchestrator module) | scirium host | n/a (in-process) | shared | horizontal with the orchestrator | Port formulas: tenant N Rocket.Chat = 30100 + N, tenant N MongoDB = 27100 + N. Tenant 1 (Wall Orthodontics) uses 30101 and 27101. @@ -24,16 +24,16 @@ URL pattern (ITPP convention): | Surface | URL | |---|---| -| Orchestrator API | https://api.wall-o.itpropartner.com | -| Orchestrator admin console | https://wall-o.itpropartner.com | -| Tenant N chat + branded PWA | https://.wall-o.itpropartner.com | +| Orchestrator API | https://api.scirium.itpropartner.com | +| Orchestrator admin console | https://scirium.itpropartner.com | +| Tenant N chat + branded PWA | https://.scirium.itpropartner.com | Caddy is the TLS edge. Each tenant subdomain gets its own site block that reverse proxies to that tenant's Rocket.Chat host port. Site blocks are generated from the tenancy table by a small render script (single source of truth in the DB, not hand-edited Caddyfile). ### 1.2 Directory and config layout ```text -/opt/wall-o/ # app code and compose, NOT /root +/opt/scirium/ # app code and compose, NOT /root ├── orchestrator/ │ ├── app/ │ │ ├── main.py # FastAPI app + routers @@ -58,7 +58,7 @@ Caddy is the TLS edge. Each tenant subdomain gets its own site block that revers └── run-backups.sh # mongodump + pg_dump to Wasabi S3 ``` -Web-served static assets (branding, PWA shell, custom CSS) live under /var/www/wall-o/ and are mounted read-only into each Rocket.Chat container. All files under /var/www/wall-o/ are chmod 644, owned by a service account, never by root home. +Web-served static assets (branding, PWA shell, custom CSS) live under /var/www/scirium/ and are mounted read-only into each Rocket.Chat container. All files under /var/www/scirium/ are chmod 644, owned by a service account, never by root home. ### 1.3 Tenant Docker Compose (Rocket.Chat + MongoDB) @@ -77,7 +77,7 @@ services: rocketchat: image: registry.rocket.chat/rocketchat/rocket.chat:7.4.0 # pinned; dev CE for Phase 0 environment: - ROOT_URL: ${ROOT_URL} # https://wall-orthodontics.wall-o.itpropartner.com + ROOT_URL: ${ROOT_URL} # https://wall-orthodontics.scirium.itpropartner.com MONGO_URL: mongodb://mongo:27017/rocketchat?replicaSet=rs0 MONGO_OPLOG_URL: mongodb://mongo:27017/local?replicaSet=rs0 PORT: "3000" @@ -90,7 +90,7 @@ services: ports: - "127.0.0.1:30101:3000" volumes: - - /var/www/wall-o/wall-orthodontics/branding:/app/branding:ro # chmod 644 + - /var/www/scirium/wall-orthodontics/branding:/app/branding:ro # chmod 644 restart: unless-stopped volumes: @@ -153,15 +153,15 @@ Facts that drive the decision: Decision: for a product we resell, use the FOSS-only build via the fossify script. MIT covers modification and commercial redistribution. The EE license restricts use and distribution, so shipping the stock image (which contains EE code) into a resold, white-labeled product is a licensing risk even if we never activate an EE key. We do not need EE features anyway: Rocket.Chat is chat transport only, and agents, retrieval, kb_scope, and the LLM all live in the orchestrator. -Consequence: maintain a private fork plus a CI job that runs fossify and builds a FOSS image (wall-o/rocketchat:foss). This is a Phase 1 gate, not a Phase 0 requirement. Phase 0 uses the stock CE image for speed, explicitly dev-only and never resold. No customer deployment ships before the FOSS image build is in CI. +Consequence: maintain a private fork plus a CI job that runs fossify and builds a FOSS image (scirium/rocketchat:foss). This is a Phase 1 gate, not a Phase 0 requirement. Phase 0 uses the stock CE image for speed, explicitly dev-only and never resold. No customer deployment ships before the FOSS image build is in CI. ### 2.2 Server rebrand steps (concrete) Because we control the FOSS source, branding is a code patch plus admin settings, not a fragile CSS-only overlay. -1. Fork Rocket.Chat and run ./fossify.sh; build wall-o/rocketchat:foss. -2. Patch the footer and login strings in the fork: replace "Powered by Rocket.Chat" and the Rocket.Chat wordmark references with the Wall-O mark, and default the site name. -3. Replace bundled logo and favicon assets with per-tenant assets served from /var/www/wall-o//branding/ (chmod 644), mounted read-only into the container. +1. Fork Rocket.Chat and run ./fossify.sh; build scirium/rocketchat:foss. +2. Patch the footer and login strings in the fork: replace "Powered by Rocket.Chat" and the Rocket.Chat wordmark references with the Scirium mark, and default the site name. +3. Replace bundled logo and favicon assets with per-tenant assets served from /var/www/scirium//branding/ (chmod 644), mounted read-only into the container. 4. In the workspace admin (Settings, Layout): set Site Name, Site URL, language, and default roles; set the custom color scheme via Custom CSS. 5. Disable telemetry, the workspace registration prompt, and the "Register" gate in the fork for self-hosted tenants. 6. Bake default colors, logo, and favicon into the image; override per tenant via mounted branding assets and admin settings. @@ -186,23 +186,23 @@ Goal: prove the core loop end to end: Rocket.Chat up, bot registered, channel cr Phase 0 uses the stock CE image for speed (dev-only). The FOSS image build from section 2.1 is a Phase 1 gate before any customer. - [ ] 1. Provision host and install Docker. `apt-get update && apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin` -- [ ] 2. Create service account and directories. `useradd -r -s /usr/sbin/nologin wallo && mkdir -p /opt/wall-o/tenants/wall-orthodontics /var/www/wall-o/wall-orthodontics/branding` +- [ ] 2. Create service account and directories. `useradd -r -s /usr/sbin/nologin scirium && mkdir -p /opt/scirium/tenants/wall-orthodontics /var/www/scirium/wall-orthodontics/branding` - [ ] 3. Write tenant compose and mongod.conf (section 1.3). Populate .env from Vaultwarden. No secrets inline. -- [ ] 4. Start the stack. `docker compose -f /opt/wall-o/tenants/wall-orthodontics/docker-compose.yml up -d` -- [ ] 5. Initialize the Mongo replica set (oplog). `docker compose -f /opt/wall-o/tenants/wall-orthodontics/docker-compose.yml exec mongo mongosh -eval "rs.initiate()"` -- [ ] 6. Verify workspace is reachable. `curl -sI https://wall-orthodontics.wall-o.itpropartner.com` returns 200 after Caddy cert issuance. -- [ ] 7. Login as admin and capture admin identity. `curl -s https://wall-orthodontics.wall-o.itpropartner.com/api/v1/login -H "Content-Type: application/json" -d '{"user":"admin","password":""}'` -- [ ] 8. Register the agent bot user. `curl -s .../api/v1/users.create -H "X-Auth-Token: " -H "X-User-Id: " -d '{"name":"Wall-O Agent","username":"wallo.agent","email":"wallo-agent@wall-orthodontics.internal","password":"","roles":["bot"],"joinDefaultChannels":false,"verified":true}'` +- [ ] 4. Start the stack. `docker compose -f /opt/scirium/tenants/wall-orthodontics/docker-compose.yml up -d` +- [ ] 5. Initialize the Mongo replica set (oplog). `docker compose -f /opt/scirium/tenants/wall-orthodontics/docker-compose.yml exec mongo mongosh -eval "rs.initiate()"` +- [ ] 6. Verify workspace is reachable. `curl -sI https://wall-orthodontics.scirium.itpropartner.com` returns 200 after Caddy cert issuance. +- [ ] 7. Login as admin and capture admin identity. `curl -s https://wall-orthodontics.scirium.itpropartner.com/api/v1/login -H "Content-Type: application/json" -d '{"user":"admin","password":""}'` +- [ ] 8. Register the agent bot user. `curl -s .../api/v1/users.create -H "X-Auth-Token: " -H "X-User-Id: " -d '{"name":"Scirium Agent","username":"scirium.agent","email":"scirium-agent@wall-orthodontics.internal","password":"","roles":["bot"],"joinDefaultChannels":false,"verified":true}'` - [ ] 9. Create a personal access token for the bot. `curl -s .../api/v1/users.createToken -H "X-Auth-Token: " -H "X-User-Id: " -d '{"userId":""}'`; store botUserId plus botAuthToken in Vaultwarden. - [ ] 10. Create the knowledge channel. `curl -s .../api/v1/channels.create -H "X-Auth-Token: " -H "X-User-Id: " -d '{"name":"employee-resources"}'` - [ ] 11. Attach the agent to the channel. `curl -s .../api/v1/channels.addOwner -H "X-Auth-Token: " -H "X-User-Id: " -d '{"roomId":"","userId":""}'` -- [ ] 12. Confirm the bot can post. `curl -s .../api/v1/chat.postMessage -H "X-Auth-Token: " -H "X-User-Id: " -d '{"roomId":"","text":"Wall-O agent online."}'` -- [ ] 13. Stand up the orchestrator skeleton plus Postgres + pgvector. `docker compose -f /opt/wall-o/orchestrator/docker-compose.yml up -d` with image pgvector/pgvector:pg16, port 127.0.0.1:5432, credentials from .env (Vaultwarden). +- [ ] 12. Confirm the bot can post. `curl -s .../api/v1/chat.postMessage -H "X-Auth-Token: " -H "X-User-Id: " -d '{"roomId":"","text":"Scirium agent online."}'` +- [ ] 13. Stand up the orchestrator skeleton plus Postgres + pgvector. `docker compose -f /opt/scirium/orchestrator/docker-compose.yml up -d` with image pgvector/pgvector:pg16, port 127.0.0.1:5432, credentials from .env (Vaultwarden). - [ ] 14. Run migrations to create tenants, channels, agents, kb_scope, documents, chunks tables (section 4.2 columns). - [ ] 15. Seed the tenants row with rocket_chat_url, rocket_chat_admin_user_id, and rocket_chat_admin_token_ref for Wall Orthodontics, and the agents row with the bot user id and bot token reference; leave all tokens in Vaultwarden only. -- [ ] 16. Upload a test document. `curl -s -F "file=@staff-handbook.pdf" -F "tenant_id=" -F "channel_id=" https://api.wall-o.itpropartner.com/v1/documents`; orchestrator stores the file and records kb_scope. +- [ ] 16. Upload a test document. `curl -s -F "file=@staff-handbook.pdf" -F "tenant_id=" -F "channel_id=" https://api.scirium.itpropartner.com/v1/documents`; orchestrator stores the file and records kb_scope. - [ ] 17. Index the document. Orchestrator chunks, embeds via admin-ai, and inserts vectors into pgvector with tenant_id plus channel_id on every row. -- [ ] 18. Retrieval smoke test. `curl -s "https://api.wall-o.itpropartner.com/v1/retrieve?tenant_id=&channel_id=&q="` returns a scoped chunk. +- [ ] 18. Retrieval smoke test. `curl -s "https://api.scirium.itpropartner.com/v1/retrieve?tenant_id=&channel_id=&q="` returns a scoped chunk. - [ ] 19. Close the chat loop. Orchestrator polls the channel via `channels.messages?roomId=` and replies through chat.postMessage using the bot identity; verify a staff question gets a grounded answer. - [ ] 20. Verify mobile. Open the tenant subdomain in a mobile browser (install the PWA) and confirm chat renders and the bot replies. - [ ] 21. Verify push. Configure Push settings in the workspace (gateway URL), send a direct message to a test user on a mobile device, confirm the notification arrives on the PWA or the Rocket.Chat mobile app pointed at the server. @@ -228,7 +228,7 @@ All components are self-hosted on netcup infrastructure in the chosen region. Ch ### 4.4 Backups -Nightly job in /opt/wall-o/backups/run-backups.sh: per-tenant mongodump (via the loopback port) plus orchestrator pg_dump, encrypted, uploaded to Wasabi S3. Retention per the ITPP backup schedule with a documented RPO. Backups are restorable per tenant, matching the isolation boundary. +Nightly job in /opt/scirium/backups/run-backups.sh: per-tenant mongodump (via the loopback port) plus orchestrator pg_dump, encrypted, uploaded to Wasabi S3. Retention per the ITPP backup schedule with a documented RPO. Backups are restorable per tenant, matching the isolation boundary. ### 4.5 Secret management diff --git a/projects/scirium/04-business-proposal.md b/projects/scirium/04-business-proposal.md index cfa26ac..3e69f39 100644 --- a/projects/scirium/04-business-proposal.md +++ b/projects/scirium/04-business-proposal.md @@ -1,8 +1,8 @@ -# Wall-O Business Proposal +# Scirium Business Proposal Status: OPEN (v1 draft, pre-critical-review) Date: 2026-08-16 -Author: Sho'Nuff (Conductor) + Wall-O marketing team +Author: Sho'Nuff (Conductor) + Scirium marketing team First client: Wall Orthodontics (pilot beachhead) Product scope: business-agnostic internal staff knowledge-base chat @@ -26,13 +26,13 @@ Product scope: business-agnostic internal staff knowledge-base chat ## 1. Executive Summary -Wall-O is a multi-tenant internal staff knowledge-base chat platform. Every knowledge domain inside a business (employee handbook, billing, IT help, policies, procedures) becomes its own scoped AI chat channel, backed by that business's real documents. Staff ask questions in a chat interface and get grounded, cited answers drawn from the company's own files - never hallucinated, never leaking across domains. +Scirium is a multi-tenant internal staff knowledge-base chat platform. Every knowledge domain inside a business (employee handbook, billing, IT help, policies, procedures) becomes its own scoped AI chat channel, backed by that business's real documents. Staff ask questions in a chat interface and get grounded, cited answers drawn from the company's own files - never hallucinated, never leaking across domains. The core problem is universal and business-agnostic: employees waste a documented, measurable fraction of their week hunting for information that already exists somewhere in the organization. McKinsey and Gartner studies put that fraction in the double digits of weekly hours. Enterprise solutions (Glean, Moveworks, Coveo) solve this for large companies at enterprise prices and enterprise procurement complexity. The SMB and vertical-niche middle - dental practices, law firms, restaurants, retail groups, logistics firms - is priced out and under-served. -Wall-O's answer is a hard invariant: one channel equals one knowledge domain, one attached AI agent, and one scoped knowledge source. This makes answers provably grounded (every reply carries citations to the source document) and provably isolated (a billing question can never surface a patient file or a neighboring tenant's data). The product is self-hosted, white-label, and business-agnostic by construction - the same core serves a 12-person dental practice and a 200-person law firm. +Scirium's answer is a hard invariant: one channel equals one knowledge domain, one attached AI agent, and one scoped knowledge source. This makes answers provably grounded (every reply carries citations to the source document) and provably isolated (a billing question can never surface a patient file or a neighboring tenant's data). The product is self-hosted, white-label, and business-agnostic by construction - the same core serves a 12-person dental practice and a 200-person law firm. -Financially, Wall-O is a high-margin software product running on infrastructure IT Pro Partner already owns: ~$68K build cost, ~$0.50 per 1,000 queries marginal cost, ~95-98% gross margin, ~$1,000 CAC against ~$14K LTV, and full build-cost payback in ~10-13 months (realistic). The v1 is a grounded Q&A assistant. The v2 roadmap adds risk-tiered "do" capabilities (reporting, content generation, integrations) that deepen the moat without ever touching patient/PHI scope. +Financially, Scirium is a high-margin software product running on infrastructure IT Pro Partner already owns: ~$68K build cost, ~$0.50 per 1,000 queries marginal cost, ~95-98% gross margin, ~$1,000 CAC against ~$14K LTV, and full build-cost payback in ~10-13 months (realistic). The v1 is a grounded Q&A assistant. The v2 roadmap adds risk-tiered "do" capabilities (reporting, content generation, integrations) that deepen the moat without ever touching patient/PHI scope. This proposal defines v1 and v2 concretely, prices it against the market, and makes the fact-based case for building it. It is submitted for critical review. @@ -40,7 +40,7 @@ This proposal defines v1 and v2 concretely, prices it against the market, and ma ## 2. Elevator Pitch -Wall-O is the AI coworker that reads your business's actual documents and answers your team's questions with citations - for the price of a streaming subscription, on infrastructure you control, scoped so nothing leaks. It is "a private, cited ChatGPT for your employee handbook, billing rules, and policies" - one tightly-scoped assistant per knowledge domain, white-labeled to your brand. +Scirium is the AI coworker that reads your business's actual documents and answers your team's questions with citations - for the price of a streaming subscription, on infrastructure you control, scoped so nothing leaks. It is "a private, cited ChatGPT for your employee handbook, billing rules, and policies" - one tightly-scoped assistant per knowledge domain, white-labeled to your brand. --- @@ -67,7 +67,7 @@ This is not an industry-specific problem. A dental practice has the same shape o | Generic LLM (public ChatGPT) | Low | High (risk) | Hallucinates, no access to internal docs, leaks data | | Enterprise knowledge AI (Glean, Moveworks, Coveo) | Low | Low (but expensive) | $30+/seat/mo, enterprise procurement, overkill for SMB | -The gap: there is no affordable, self-hosted, white-label answer for the SMB and vertical-niche middle. Enterprise tools solve the problem but are priced and packaged for enterprises. Public LLMs are cheap but ungrounded and unsafe for internal documents. Wall-O sits in that gap. +The gap: there is no affordable, self-hosted, white-label answer for the SMB and vertical-niche middle. Enterprise tools solve the problem but are priced and packaged for enterprises. Public LLMs are cheap but ungrounded and unsafe for internal documents. Scirium sits in that gap. ### 3.3 The precise target user @@ -80,9 +80,9 @@ The buyer is the owner or office manager of an SMB (10 to 200 employees) who: The beachhead vertical is orthodontics/dental (Wall Orthodontics), but the product model is explicitly business-agnostic - the same channel primitive serves any document-driven business. -### 3.4 The gap Wall-O fills +### 3.4 The gap Scirium fills -| Need | Public LLM | Enterprise AI | Wall-O | +| Need | Public LLM | Enterprise AI | Scirium | |---|---|---|---| | Grounded, cited answers from my docs | No | Yes | Yes | | Affordable for SMB | Yes (but unsafe) | No | Yes | @@ -116,7 +116,7 @@ Sources: ~1B global knowledge workers (Schroders); ~100M US knowledge workers (U - AI in Knowledge Management: $6.7B (2023) to $62.4B (2033), **25% CAGR** (Market.us). - Knowledge Management Software: $14.56B (2025) to $70.01B (2035), **16.9% CAGR**, fastest segment "intelligent chatbots and virtual agents" (MRFR). - Enterprises deploying internal AI chatbots report **45-55% reduction in query resolution time** (MRFR). -- SMB AI adoption rose from 5.2% (Jan 2023) to 17.7% (end 2025), with entry cost falling to $20-30/mo (JPMorgan Chase Institute). The demand is rising and the price point is coming to Wall-O's band. +- SMB AI adoption rose from 5.2% (Jan 2023) to 17.7% (end 2025), with entry cost falling to $20-30/mo (JPMorgan Chase Institute). The demand is rising and the price point is coming to Scirium's band. ### 4.3 Real-world examples (the fact-based case to build) @@ -135,19 +135,19 @@ On the "every business has this problem" claim, the independent studies converge - IDC: ~2.5 hours/day, ~30% of the workday, spent searching; 60% of executives say staff could not find what they needed. - Deloitte: **>25% of time** spent searching for information. -These cluster around 20-30% of the workday lost to search - a universal, business-agnostic cost, not an enterprise-only one. That is the budget Wall-O attacks. +These cluster around 20-30% of the workday lost to search - a universal, business-agnostic cost, not an enterprise-only one. That is the budget Scirium attacks. ### 4.4 Why the SMB/vertical segment is underserved 1. Enterprise tools price SMBs out on purpose. Glean is ~$50-75/seat with a 100-seat minimum (~$60K/yr floor); M365 Copilot is $30/seat on top of a required M365 license; Moveworks is $100K+/yr; Coveo is opaque enterprise QPM. None serve a 10-30 person practice. 2. SMB AI budgets are tiny - median ~$28-50/month total (JPMorgan Chase Institute). A $60K/yr enterprise contract is 100x an SMB's entire AI budget. -3. Only 17.7% of SMBs had adopted AI by end-2025, versus near-universal experimentation in large enterprises - while 91% of AI-using SMBs report revenue impact (Salesforce). The wedge is a cheap, self-hosted, vertical-aware tool - exactly Wall-O. +3. Only 17.7% of SMBs had adopted AI by end-2025, versus near-universal experimentation in large enterprises - while 91% of AI-using SMBs report revenue impact (Salesforce). The wedge is a cheap, self-hosted, vertical-aware tool - exactly Scirium. ### 4.5 Competitive landscape (condensed) Full 10-competitor analysis is in the research appendix. The key fact: **the $300-800/month self-hosted band for 10-30 seat SMBs is structurally empty.** -| Competitor | Pricing | Target | Wall-O's gap | +| Competitor | Pricing | Target | Scirium's gap | |---|---|---|---| | Glean | $50-75/seat, 100-seat min (~$60K/yr) | Enterprise | Self-host + white-label + vertical templates + SMB price | | Moveworks/ServiceNow | $100K+/yr | Enterprise IT/HR | Not ticket-automation; general internal knowledge | @@ -160,16 +160,16 @@ Full 10-competitor analysis is in the research appendix. The key fact: **the $30 Two strategic notes from the research: -1. The two tools an SMB owner already has are **M365 Copilot and Notion AI** - so Wall-O must lead with self-hosted data control + vertical specificity, not generic "AI chat over docs", which those already do. -2. **No competitor is white-label.** That is the cleanest MSP/reseller angle - ITPP can sell Wall-O under a partner's brand where Glean/Guru/Notion/Copilot cannot. +1. The two tools an SMB owner already has are **M365 Copilot and Notion AI** - so Scirium must lead with self-hosted data control + vertical specificity, not generic "AI chat over docs", which those already do. +2. **No competitor is white-label.** That is the cleanest MSP/reseller angle - ITPP can sell Scirium under a partner's brand where Glean/Guru/Notion/Copilot cannot. --- ## 5. Product Overview -### 5.1 The core primitive (what makes Wall-O different) +### 5.1 The core primitive (what makes Scirium different) -Every Wall-O channel is exactly three things bound together, and this is a hard invariant: +Every Scirium channel is exactly three things bound together, and this is a hard invariant: 1. One knowledge domain (e.g. "Employee Resources", "Billing", "IT Help"). 2. One attached AI agent (a domain-tuned persona). @@ -232,7 +232,7 @@ v2 adds risk-tiered "do" capabilities on top of the v1 answer engine. These are | Reporting (structured extraction + SQL aggregation + chart render) | Reporting | Zero new write risk | Yes | Highest value, zero risk - recommended first v2 ship | | Content generation (drafts, summaries, boilerplate) | Content generation | Drafts only | Yes | Saves drafting time | | Housekeeping (move/rename/delete-to-recycle) | Housekeeping | Destructive | No - propose/approve/audit | Keeps knowledge fresh | -| Integrations (Graph delegated sendMail/calendar/webhooks) | Integrations | External side effects | No - approval | Connects Wall-O to workflows | +| Integrations (Graph delegated sendMail/calendar/webhooks) | Integrations | External side effects | No - approval | Connects Scirium to workflows | | Design/brand (template render + image gen) | Design/brand | Drafts only | Yes (template-driven only) | Flyers, branded assets | **Write rails (SETTLED):** destructive actions require propose -> approve -> narrow audited write with before/after and undo path. Harmless writes auto-approve by risk tier. Per-agent tool scoping preserves one-agent-one-domain. Template-driven rendering is required for text-accurate flyers; raw image generation is unreliable for text and is not shipped for that use. @@ -249,7 +249,7 @@ The v1 and v2 product model references no industry. "Tenant" is any business; "c ### 6.1 Pricing philosophy -Premium positioning, not race-to-bottom. Wall-O is "the most accurate, best-scoped internal knowledge assistant", not the cheapest. Price for value delivered (time saved, errors avoided), not competitor undercutting. The product is self-hosted software with high gross margin, so price is set by willingness-to-pay in the segment, not by our marginal cost. +Premium positioning, not race-to-bottom. Scirium is "the most accurate, best-scoped internal knowledge assistant", not the cheapest. Price for value delivered (time saved, errors avoided), not competitor undercutting. The product is self-hosted software with high gross margin, so price is set by willingness-to-pay in the segment, not by our marginal cost. ### 6.2 Tiers (from the financial model) @@ -274,11 +274,11 @@ Blended ARPU at a 60/30/10 tier mix = $469/mo (modeled at $450 for safety). Ever ### 7.1 The hard invariant is the moat -The one-channel-one-agent-one-scope invariant is not a feature a competitor can bolt on after the fact; it is the schema. It makes every answer provably grounded and provably isolated, and it is what lets Wall-O serve regulated-adjacent verticals (dental, legal) where data leakage is a dealbreaker. Enterprise tools do broad search over everything; Wall-O does scoped answers over exactly one domain. +The one-channel-one-agent-one-scope invariant is not a feature a competitor can bolt on after the fact; it is the schema. It makes every answer provably grounded and provably isolated, and it is what lets Scirium serve regulated-adjacent verticals (dental, legal) where data leakage is a dealbreaker. Enterprise tools do broad search over everything; Scirium does scoped answers over exactly one domain. ### 7.2 SMB price point with enterprise-grade isolation -Wall-O pairs SMB affordability with the isolation discipline usually found only in enterprise platforms. That combination is the open gap in the market. +Scirium pairs SMB affordability with the isolation discipline usually found only in enterprise platforms. That combination is the open gap in the market. ### 7.3 Self-hosted and white-label @@ -286,7 +286,7 @@ Data never leaves the customer's estate (or ITPP's controlled netcup estate). Ch ### 7.4 Distribution via existing ITPP MSP -IT Pro Partner already runs the infrastructure and has the MSP relationship model. Wall-O is not a cold-start consumer product; it slots into an existing managed-services motion where the first customer (Wall Orthodontics) is already warm. +IT Pro Partner already runs the infrastructure and has the MSP relationship model. Scirium is not a cold-start consumer product; it slots into an existing managed-services motion where the first customer (Wall Orthodontics) is already warm. ### 7.5 The moat compounds in v2 @@ -332,7 +332,7 @@ Sell through IT Pro Partner's managed-services relationships and peer referral ( ### 9.1 The one risk that kills the product -Hallucination. If Wall-O ever gives staff a wrong, confidently-stated answer about policy or billing, trust collapses and the product is done. The never-fabricate rail, mandatory citations, and below-threshold "I could not find an answer" behavior are not features - they are the product. This is why the answer engine ships before any "do" capability, and why the v2 write features are risk-tiered with approval gates. +Hallucination. If Scirium ever gives staff a wrong, confidently-stated answer about policy or billing, trust collapses and the product is done. The never-fabricate rail, mandatory citations, and below-threshold "I could not find an answer" behavior are not features - they are the product. This is why the answer engine ships before any "do" capability, and why the v2 write features are risk-tiered with approval gates. --- @@ -400,7 +400,7 @@ Sensitivity: even at V4 Pro rates ($0.435/$0.87) it is $1.31/1K queries; a 5x pr **Yes - build it.** The math is unambiguous because three things compound: 1. Near-zero marginal cost (~$0.50 per 1,000 queries) on self-hosted infra and open components - no license fees, no per-seat third-party cost. -2. ~95-98% gross margin with premium pricing in a market that already has real floors (Glean ~$60K/yr minimum, Moveworks $100K+). Wall-O at $199-$2,000/mo is dramatically cheaper to the customer yet ~98% margin to us. +2. ~95-98% gross margin with premium pricing in a market that already has real floors (Glean ~$60K/yr minimum, Moveworks $100K+). Scirium at $199-$2,000/mo is dramatically cheaper to the customer yet ~98% margin to us. 3. Owned distribution: ITPP already has the MSP client base and trust, so CAC is ~$1,000/tenant instead of a paid-acquisition crawl. Full payback in ~10-13 months realistic, profitable even in the conservative case within ~2 years. The honest caveats: the M365 connector is the riskiest engineering line (fund and pilot it first), DeepSeek may raise prices (LiteLLM abstraction absorbs it), and churn/adoption are unproven in a new category (activation, queries-per-active-user, is the KPI to watch). @@ -415,7 +415,7 @@ The build requires, and the design docs already specify: | Infrastructure | Status | Detail | |---|---|---| -| netcup host for Wall-O | To provision | Docker host, Caddy TLS edge, one Rocket.Chat workspace + MongoDB per tenant | +| netcup host for Scirium | To provision | Docker host, Caddy TLS edge, one Rocket.Chat workspace + MongoDB per tenant | | Orchestrator (FastAPI) | To build | Multi-tenant, owns tenancy/agents/scopes/retrieval/LLM | | Postgres + pgvector | To build | Tenancy tables, chunks + HNSW vector index | | admin-ai (LiteLLM) | Existing | DeepSeek V4 Pro primary + fallback chain | diff --git a/projects/scirium/05-vision-and-positioning.md b/projects/scirium/05-vision-and-positioning.md index 40b9dae..708d273 100644 --- a/projects/scirium/05-vision-and-positioning.md +++ b/projects/scirium/05-vision-and-positioning.md @@ -1,7 +1,7 @@ # Scirium: Vision, Positioning, and Roadmap Status: PLANNED (design-only, no code yet) -Brand: Scirium (formerly codenamed Wall-O, retired 2026-08-16) +Brand: Scirium (product name finalized 2026-08-16) Domain: scirium.com First client: Wall Orthodontics (pilot) @@ -62,7 +62,7 @@ The gap between v1 and v3/v4 is autonomy, not accuracy. v1 is already fully grou ## 7. Current State -Design-only. No code, no orchestrator, no containers. The business proposal and critical review are deployed (under the legacy /wall-o/ URL, pending redeploy to /scirium/). The pilot is Wall Orthodontics, an orthodontic practice using Microsoft 365, for internal staff knowledge only. +Design-only. No code, no orchestrator, no containers. The business proposal and critical review are deployed under the /scirium/ URL. The pilot is Wall Orthodontics, an orthodontic practice using Microsoft 365, for internal staff knowledge only. Hard scope, non-negotiable: internal staff documentation. No patient records, no PHI, no HIPAA scope, no medical or vision AI. X-ray and clinical image review is a separate, FDA-regulated product and is permanently outside Scirium. diff --git a/projects/scirium/docs/01-overview.md b/projects/scirium/docs/01-overview.md new file mode 100644 index 0000000..f4d67a1 --- /dev/null +++ b/projects/scirium/docs/01-overview.md @@ -0,0 +1,75 @@ +# Scirium: Product Overview + +Status: PLANNED +Audience: everyone (technical and business). Read this first. + +## 1. One-liner + +Ask your company anything. Get a cited answer from your own documents, scoped to the exact department you are talking to. + +## 2. What Scirium Is + +Scirium is a self-hosted, white-label, multi-tenant knowledge assistant for internal staff. A company points Scirium at its own document libraries (SharePoint, OneDrive, employee handbooks, policies, procedures). Staff ask questions in a chat window. Scirium answers using only that company's documents, and every answer carries inline citations pointing to the source. + +Scirium is pronounced "sigh-ree-um", from the Latin "scire" (to know) plus the -ium element suffix. + +## 3. Who It Is For + +| Audience | What they need from this product | +|---|---| +| Staff (end users) | Correct, cited answers to policy, procedure, and how-to questions without interrupting a human. | +| Practice / business admins | A way to turn existing documents into a scoped, auditable Q&A assistant per department. | +| MSP / reseller partners | A white-label product they sell under their own brand on infrastructure they control. | +| IT Pro Partner (operator) | A multi-tenant service that runs on existing netcup infrastructure with high gross margin. | + +## 4. The Core Invariant + +One channel equals one knowledge domain plus one agent plus one scoped source. This is a hard rule, enforced in the data model, not a policy. + +| Bound item | Meaning | +|---|---| +| One knowledge domain | Employee Resources, Billing, IT Help, or similar. | +| One agent | A domain-tuned persona that answers only within that domain. | +| One scoped source | A set of M365 document libraries mapped to one vector namespace. | + +A channel cannot span two domains, and an agent cannot serve two channels. If a business needs a second domain, it creates a second channel, a second agent, and a second scope. + +## 5. Why This Is Not Just Another Chatbot + +A regular chatbot is one undifferentiated model with no grounding in your documents, no audit trail, and no scoping. Scirium is the opposite on every axis a business cares about. + +| Axis | Regular chat | Scirium | +|---|---|---| +| Grounding | May hallucinate, no source | Every answer cites its source documents inline with a Sources footer | +| Scoping | One model answers everything | One channel equals one domain plus one agent plus one scoped source. Billing answers billing, HR answers HR. | +| Data residency | Sent to a vendor's cloud | Self-hosted, white-label, data stays in the company's M365 and your infra | +| Audit trail | None | Every question and answer logged with citations, model, tokens, latency | +| Identity | Anonymous | Each domain is a named agent persona (for example "Scirium Billing") | +| Failure mode | Confident wrong answers | If the answer is not in scope, it says so instead of guessing | +| Tenancy | N/A | One deployment serves many isolated tenants | + +The difference is trust. A regular chatbot is a tool. Scirium is a scoped, grounded, audited answer layer over documents the company already owns. + +## 6. Architecture at a Glance + +| Layer | Responsibility | +|---|---| +| Rocket.Chat | Chat transport only. One workspace per tenant. Zero intelligence. | +| FastAPI orchestrator | All intelligence. Tenancy, agents, scopes, M365 connector, retrieval, LLM. | +| Postgres + pgvector | State and vectors. Tenants, channels, agents, scopes, documents, chunks, messages. | +| admin-ai | LLM. DeepSeek V4 Pro primary with a configured fallback chain. | +| Wasabi S3 | Object storage. Sync staging, backups, agent assets, audit exports. | + +This split is fixed. Rocket.Chat never holds intelligence; the orchestrator never renders chat UI. + +## 7. Hard Scope + +Internal staff documentation only. No patient records, no PHI, no HIPAA scope, no medical or vision AI. This boundary is permanent and is not a roadmap item. + +## 8. Related Documents + +- 02-v1-scope.md: exactly what v1 ships. +- 03-v2-scope.md: what v2 adds. +- 04-admin-guide.md: provisioning and go-live. +- 05-user-guide.md: how staff use it. +- 06-roadmap.md: v1 through v4 and the autonomy curve. diff --git a/projects/scirium/docs/02-v1-scope.md b/projects/scirium/docs/02-v1-scope.md new file mode 100644 index 0000000..0eb1eaf --- /dev/null +++ b/projects/scirium/docs/02-v1-scope.md @@ -0,0 +1,67 @@ +# Scirium v1 Scope + +Status: PLANNED +Applies to: v1 (grounded cited Q&A only) + +## 1. What v1 Ships + +v1 is a read-only, grounded, cited question answering assistant. A staff member asks a question in chat. Scirium retrieves the relevant passages from that channel's scoped M365 document libraries and returns an answer with inline citations to the source documents. + +v1 ships exactly one capability: grounded, cited Q&A. Nothing else. + +| Capability | In v1? | Notes | +|---|---|---| +| Grounded, cited Q&A | Yes | The core and only capability. | +| Read-only retrieval over scoped M365 libraries | Yes | SharePoint and OneDrive libraries named in the channel's scope. | +| Autonomous actions (send, write, create, update) | No | Zero. No writes to M365, no message posting beyond the answer, no integrations. | +| Report generation, content drafts, workflows | No | Deferred to v2 and later. | +| Patient records or PHI | No | Permanently out of scope, every version. | + +## 2. The v1 Contract + +- Every answer cites its sources inline and in a Sources footer. +- If the answer is not in the knowledge base, Scirium says so instead of guessing. +- Scirium never writes to the source systems. The M365 connector holds read permission only. +- Every question and answer is logged for audit. + +## 3. The 6-Step Message Flow + +1. Staff post a question, either by @mentioning the agent in a channel or by DMing the bot. +2. Rocket.Chat fires an outgoing webhook to the orchestrator (channel path) or the bot listener delivers a DM event (DM path). +3. The orchestrator authenticates the request, then resolves tenant, channel, agent, and scope from the room and webhook path. +4. Retrieval: a pgvector semantic search over the channel's vector namespace returns candidate chunks, reranked to the top set. A below-threshold result falls back to Microsoft Graph search over the scope's libraries. +5. The orchestrator builds a prompt from the agent persona, the retrieved context with source markers, and the citation instruction, then calls admin-ai (DeepSeek V4 Pro primary with fallback). +6. The answer is posted back to Rocket.Chat as the agent bot, with inline citations and a Sources footer. + +## 4. Retrieval Details + +| Step | Behavior | +|---|---| +| Primary | pgvector cosine search filtered by tenant_id and kb_scope_id in the same query. | +| Candidate set | Top 20 by score. | +| Rerank | Top 5 passed to the prompt. | +| Fallback | Below threshold or empty: Microsoft Graph /search/query over the scope's document_libraries. | +| Isolation | tenant_id and kb_scope_id filters are mandatory, so a chunk can never leak across channels or tenants. | + +## 5. Error Handling + +| Condition | v1 behavior | +|---|---| +| Retrieval empty or below threshold | Reply "I could not find an answer in the knowledge base for this question", no sources, never guess. | +| LLM timeout or error | Retry once on the fallback model, then a canned "could not reach the model" reply. | +| Channel has no agent or no scope | Configuration error reply (or silent no-op, per tenant config). | +| Webhook retry (duplicate) | Idempotency key deduplicates; the duplicate returns 200 and is dropped. | +| Post failure | Retry with backoff, then mark failed and surface a tenant alert. | + +## 6. Explicit v1 Exclusions + +v1 does none of the following, and this is intentional: + +- No actions. v1 cannot send email, create calendar items, update records, or write to any system. +- No writes to M365. The connector is read-only. +- No patient records or PHI, ever. +- No multi-domain answers. A channel answers only its own scope. +- No proactive messages. The bot replies only to a question addressed to it. +- No role escalation. An answer cannot grant itself new capabilities. + +Everything on this list is either permanently excluded (PHI) or deferred to a later version behind the propose-approve-audit gate. diff --git a/projects/scirium/docs/03-v2-scope.md b/projects/scirium/docs/03-v2-scope.md new file mode 100644 index 0000000..aaf79af --- /dev/null +++ b/projects/scirium/docs/03-v2-scope.md @@ -0,0 +1,62 @@ +# Scirium v2 Scope + +Status: PLANNED +Applies to: v2 (risk-tiered actions on top of v1) + +## 1. What v2 Adds + +v2 keeps everything in v1 (grounded, cited, read-only Q&A) and adds a single new capability class: risk-tiered actions. v2 never removes the v1 grounding rails. + +## 2. Risk-Tiered Actions + +Actions are grouped by risk and ship in that order. Reporting first, low-risk writes second, and never anything above the approved tier. + +| Tier | Examples | Ships | Autonomy | +|---|---|---|---| +| 0 | Q&A only (v1) | v1 | None | +| 1 | Reporting: summaries, compliance checklists, document search reports | v2 first | None beyond read | +| 2 | Low-risk writes: draft a policy section, draft an email reply, update an internal FAQ | v2 second | Propose, then approve, then narrow audited write | +| 3 | Higher-risk writes and integrations | v3 | Still gated, broader by tier | + +## 3. The Propose-Approve-Audit Gate + +Every action in v2 and later passes through three steps. This gate is permanent. + +1. Propose. The agent drafts the action and shows exactly what it would do: the target system, the record, and the exact change. +2. Approve. A human with the right role approves or rejects. No action executes without an explicit approval. +3. Audit. The executed action is written narrowly (only the approved change), and the full record is logged: who proposed, who approved, what changed, when. + +| Gate step | What it enforces | +|---|---| +| Propose | The agent never acts silently; it always shows the plan first. | +| Approve | A human is in the loop for every action, every time. | +| Audit | Every executed action is logged and replayable from the audit trail. | + +## 4. Reporting First, Writes Second + +v2 ships reporting before writes because reporting is read-only and low risk. Reporting proves the pipeline end to end (propose, approve, audit) before the product is allowed to touch any system. + +Low-risk write examples (tier 2, all gated): + +- Draft a section of an employee handbook for an admin to review. +- Draft a reply to a customer email that a human then sends. +- Update an internal FAQ entry with an approved wording change. + +Each example follows propose, approve, narrow write, audit. None of them are autonomous. + +## 5. Permanent Autonomy Guardrails + +These hold for v2 and every later version: + +- The propose-approve-audit gate is never removed or bypassed. +- Writes are always narrow: only the approved field or record, nothing else. +- Risk tier is a hard ceiling. A channel cannot act above its assigned tier. +- Patient records and PHI remain permanently out of scope. +- Every action is logged in the messages and audit tables with the approver identity. + +## 6. What v2 Does Not Do + +- No free-roaming agents that act across channels or systems. +- No writes without a prior human approval. +- No patient or PHI content, regardless of tier. +- No removal of the v1 grounding and citation rails. diff --git a/projects/scirium/docs/04-admin-guide.md b/projects/scirium/docs/04-admin-guide.md new file mode 100644 index 0000000..8d88a46 --- /dev/null +++ b/projects/scirium/docs/04-admin-guide.md @@ -0,0 +1,76 @@ +# Scirium Admin Guide + +Status: PLANNED +Audience: tenant admin and Scirium operator +Purpose: provision a tenant and take a channel live end to end. + +## 1. Prerequisites + +- A Microsoft 365 tenant with the Scirium Entra app registered and holding the Sites.Selected application permission. +- A Rocket.Chat workspace provisioned for the tenant (one workspace per tenant). +- Vaultwarden access for secrets (M365 credentials, bot tokens, webhook secret). +- Admin role on the orchestrator. + +## 2. Provision a Tenant + +1. Create the tenants row: slug, name, branding (logo_url, accent_color), M365 tenant id and client id. +2. Store the M365 client secret in Vaultwarden; put only the reference in m365_credential_ref. +3. Record the Rocket.Chat workspace root URL in rocket_chat_url. +4. Generate a webhook signing secret, store it in Vaultwarden, and set webhook_secret_ref. +5. Set status to provisioning until the workspace and connector are confirmed. + +The tenant is now the root of the tenancy tree. Every downstream object hangs off it. + +## 3. Create a Channel + +1. Insert a channels row: name (the knowledge domain, for example "Billing"), slug (unique per tenant), description. +2. Optionally create the matching Rocket.Chat room and store rocket_chat_room_id and rocket_chat_room_name. +3. Leave status = draft. The channel stays draft until the scope is bound and indexed. + +## 4. Attach an Agent + +1. Insert an agents row: name (for example "Scirium Billing"), system_prompt (the domain persona), model_name (deepseek-v4-pro) and fallback_model, rocket_chat_bot_username. +2. Provision the Rocket.Chat bot user (POST /api/v1/users.create with roles bot), create a personal access token, and store the token reference and bot user id. +3. Invite the bot to the room (POST /api/v1/channels.invite). +4. Set channels.agent_id to the new agent. + +## 5. Bind a Scope + +1. Insert a kb_scopes row: vector_namespace (tenant_{tenant_id}__scope_{kb_scope_id}), document_libraries (the allowlisted M365 site and drive ids), embedding_model and embedding_dim, chunk_size (512) and chunk_overlap (64). +2. Set channels.kb_scope_id to the new scope. + +The scope is the allowlist. Only the libraries named here are ever indexed or searched for this channel. + +## 6. Run the Initial Sync + +1. Trigger the M365 connector for the scope. It pulls the named document libraries, extracts text, chunks, embeds, and writes documents and chunks rows under the namespace. +2. Monitor document status: pending to extracting to indexing to indexed. +3. Confirm nonzero indexed document count and nonzero chunk count in the scope's namespace. +4. The channel stays in draft until this succeeds. + +This is the only long-running step. Everything before it is fast and idempotent. + +## 7. Go Live + +1. Set channels.status = active. +2. Configure the outgoing webhook on the channel with the trigger word set to the bot username, pointing at the orchestrator webhook URL. +3. Optionally register a slash command such as /ask. +4. Run an end-to-end smoke test: ask a question in the channel, confirm the agent bot posts a cited answer, and confirm the answer's sources resolve to documents inside the scope. +5. Verify a below-threshold question returns "I could not find an answer in the knowledge base for this question" instead of guessing. + +## 8. Operate + +| Task | Where | +|---|---| +| Delta sync schedule | kb_scopes.sync_policy | +| Document failure triage | documents.status and documents.error | +| Audit review | messages table (question, answer, citations, model, latency) | +| Secret rotation | Vaultwarden; update only the reference in Postgres | +| Suspend a tenant | tenants.status = suspended | + +## 9. Rules + +- Never inline a secret in Postgres or config. References only. +- Never index a library outside the scope allowlist. +- Never go live on an empty scope. Indexed document count must be nonzero. +- Never grant the connector write permission. Read only. diff --git a/projects/scirium/docs/05-user-guide.md b/projects/scirium/docs/05-user-guide.md new file mode 100644 index 0000000..4712497 --- /dev/null +++ b/projects/scirium/docs/05-user-guide.md @@ -0,0 +1,53 @@ +# Scirium User Guide + +Status: PLANNED +Audience: staff (end users) + +## 1. How to Ask + +You can reach an agent two ways: + +| Mode | Use it for | How | +|---|---|---| +| Channel @mention | Questions the whole team benefits from; answers stay searchable in the room | Type @ followed by the agent name, then your question. | +| DM the bot | Private follow-up, clarification, or a 1:1 thread | Open a direct message with the agent bot and type your question. | + +Both paths produce the same cited answer format. Only the destination differs. + +## 2. What a Good Question Looks Like + +Ask a complete question about a specific topic in the channel's domain. For example, in the Billing channel, ask "What is our refund policy on a disputed charge?" rather than "refund?". + +## 3. How Citations Work + +Every answer cites its sources in two places: + +1. Inline markers, such as [1], [2], next to the sentences they support. +2. A Sources footer at the end of the answer listing each cited document title and a link. + +Click the source link to open the document and verify the answer yourself. This is the point of the product: you can always check the source. + +## 4. When the Answer Says It Is Not in the Knowledge Base + +If the answer says "I could not find an answer in the knowledge base for this question", it means one of: + +| Reason | What to do | +|---|---| +| The document is not in this channel's scope | Ask in the right channel, or ask an admin to add the document to the scope. | +| The question is outside this channel's domain | Ask the matching channel (for example HR questions go to the Employee Resources channel). | +| The answer genuinely is not documented | Ask a human, or ask an admin to add the missing document. | + +Do not rephrase and expect a guess. Scirium is designed to say it does not know rather than invent an answer. + +## 5. What Scirium Cannot Do + +- It cannot answer from documents outside the channel's scope. +- It cannot answer questions about patient records or personal health information. +- It cannot take actions on your behalf (v1). It answers questions only. +- It cannot invent an answer when the source is missing. + +## 6. Tips + +- Keep a question to one topic for the clearest citations. +- If the answer is close but not quite right, DM the bot a follow-up with more detail. +- If a source link does not open, report it to an admin; the document may have moved or been removed from the scope. diff --git a/projects/scirium/docs/06-roadmap.md b/projects/scirium/docs/06-roadmap.md new file mode 100644 index 0000000..1f2c651 --- /dev/null +++ b/projects/scirium/docs/06-roadmap.md @@ -0,0 +1,38 @@ +# Scirium Roadmap + +Status: PLANNED +Audience: technical and business + +## 1. Version Curve + +| Version | Capability | Autonomy | +|---|---|---| +| v1 | Grounded, cited Q&A. Read-only retrieval over scoped M365 libraries. No actions. | Zero writes, answer only | +| v2 | Risk-tiered actions. Reporting first, then low-risk writes behind propose-approve-audit. | Conditional, human approved | +| v3 | Broader autonomous actions by risk tier, deeper connectors, granular per-channel permissions. | Tiered autonomy | +| v4 | Multi-connector breadth, analytics, admin self-service at scale. | Mature, governed | + +## 2. What Changes Between Versions + +Later versions add autonomy, not accuracy. v1 is already fully grounded and cited. v2 through v4 add the ability to act, and only within an approved risk tier. + +| Version | Adds | Does not change | +|---|---|---| +| v1 | Cited Q&A | Grounding, scoping, isolation | +| v2 | Reporting and low-risk writes | Grounding rails, approval gate | +| v3 | More connectors and tiers | One channel one domain invariant | +| v4 | Analytics and self-service | Hard scope (no PHI) | + +## 3. The Permanent Gate + +The propose-approve-audit gate is permanent across all versions. Later versions add autonomy but never remove or bypass this gate. + +1. Propose: the agent shows exactly what it would do. +2. Approve: a human approves or rejects. Nothing executes without approval. +3. Audit: the narrow, approved write executes and is logged. + +No version of Scirium becomes a free-roaming agent. Autonomy expands by risk tier, and the gate stays. + +## 4. Hard Scope, All Versions + +Internal staff documentation only. No patient records, no PHI, no HIPAA scope, no medical or vision AI. This boundary is not on the roadmap; it is permanent.