Spaces:
Running
Download docs/SAAS_PLATFORM.md from GaryLeckey/aureon-os: direct link, hf CLI and curl.
- Browser
- Download file 23 kB
-
https://huggingface.co/spaces/GaryLeckey/aureon-os/resolve/main/docs/SAAS_PLATFORM.md
- Command line
-
hf download hf://spaces/GaryLeckey/aureon-os/docs/SAAS_PLATFORM.md
-
curl -L -o SAAS_PLATFORM.md https://huggingface.co/spaces/GaryLeckey/aureon-os/resolve/main/docs/SAAS_PLATFORM.md
Aureon SaaS Platform β connected Β· working Β· categorized
The platform layer that turns the 715-module organism into a coherent product surface. It surfaces the repo β it does not rewrite it. Every system is categorized, every domain has a canonical entry point, and health is reported honestly (degraded where deps are missing, not everything-green).
This is Phase 6A of the production program. It builds on the Production-Grade Program (the two-tier gate and serving surface) and the Aureon Operator Switchboard (the grounded cognition front door), reusing both rather than duplicating them.
The shape of the problem
Three things already existed and only needed connecting:
| Layer | Already present | Role |
|---|---|---|
| Tenant / auth / billing | Supabase backend (supabase/) β auth, RBAC, per-user encrypted exchange keys, prepaid "gas-tank" credits, ~101 edge functions, 58 migrations |
The multi-tenant foundation. Reused, not rebuilt. |
| Catalog UI | React console (frontend/, Vite + TS + shadcn) grouped by the 6 product domains |
Already a systems console β but starved of data (the manifest JSONs it fetches didn't exist). |
| Categorizer | SystemRegistry (aureon/command_centers/aureon_system_hub.py) β 12 capability categories Γ per-module metadata |
The classification engine. |
| Health surfaces | SystemCoordinator.get_coordination_state(), get_operational_core().get_health() |
Live status inputs. |
The gap: there was no unified Python HTTP gateway producing a categorized
catalog + live status to feed the frontend, and nothing bridging the
single-tenant Python engine to the Supabase tenant layer. aureon/saas/ is
exactly that bridge.
Three taxonomies, reconciled
The repo describes itself three ways. The catalog maps all three onto each other:
6 product domains 24 filesystem domains 12 capability categories
(what the console groups) (folders under aureon/) (SystemRegistry semantics)
βββββββββββββββββββββββββ βββββββββββββββββββββββββ ββββββββββββββββββββββββββ
trading βββββββ trading, exchanges, β Exchange Clients
accounting scanners, strategies β¦ β Market Scanners
research ββββΊ Execution Engines
cognition βββββββ operator, cognition, β Neural Networks
security queen, bots_intelligence β Stargate & Quantum
self-improvement β¦ β Codebreaking & Harmonics Β· β¦
- Product domain β filesystem domain:
domains._FS_TO_PRODUCT(unmapped βself-improvement). - Capability category β module:
SystemRegistryclassification, or the stdlib keyword classifier (catalog._CATEGORY_RULES) when the registry can't load.
Package layout β aureon/saas/
| Module | Responsibility | Key entry points |
|---|---|---|
catalog.py |
Categorized. Build the normalized catalog; emit frontend manifests. | build_catalog(), write_frontend_manifests() |
domains.py |
Connected. Canonical entry point per domain + cheap reachability probe. | domain_report(), probe_domain(), product_domain_for() |
status.py |
Working. Honest health rollup, no heavy boot. | get_platform_status() |
gateway.py |
HTTP surface + optional Supabase tenancy bridge. | register_saas_routes(app), verify_supabase_jwt() |
catalog.py β categorized
build_catalog(workspace=REPO_ROOT) prefers the repo's SystemRegistry (richer
metadata: LOC, dashboard/thought-bus/Queen flags). If the registry can't import
β e.g. psutil absent in a lean environment β it falls back to a self-contained
stdlib scanner (_scan_builtin) that walks aureon/ and classifies by keyword
rules. The catalog never collapses to zero categories; production always
categorizes. Result is cached to state/aureon_saas_catalog.json (gitignored).
write_frontend_manifests() emits the two JSONs the React console already fetches,
shaped to the frontend's TypeScript interfaces:
aureon_saas_system_inventory.jsonβ every system as a surface withid Β· path Β· name Β· kind Β· domain Β· purpose Β· owner_subsystem Β· wiring_status Β· safety_class Β· auth_requirement Β· called_apis, grouped by product domain.aureon_organism_runtime_status.jsonβ one pulse per product domain (status + system_count + categories), live when a status snapshot is passed in.
Manifest ownership (post-unification): the checked-in static copies in
frontend/public/ are owned by the repo's manifest pipeline
(scripts/validation/generate_*), which emits a richer schema
(schema_version, entrypoint_status, imports/exports, runtime_route, β¦).
The gateway serves its own live-rendered manifests at GET /api/manifests/<name>
and does not overwrite the static files unless
AUREON_WRITE_STATIC_MANIFESTS=1 is set (boot write and
POST /api/manifests/refresh both honour this). The console fetches live first
and falls back to the static copies.
domains.py β connected
Each of the 24 filesystem domains gets a canonical entry point in _ADAPTERS
(get_operational_core, get_queen, run_operator, AureonCognition,
get_feed_hub, β¦). probe_domain() checks reachability with
importlib.util.find_spec β an import-spec check, no construction β so the
report is cheap and side-effect-free. Domains without a clean singleton fall back
to "is the package importable".
status.py β working (honestly)
get_platform_status() composes per-domain reachability + the operational core's
own health snapshot + (if present) coordinator state, and rolls reachability up
into per-product-domain status (ready / degraded / down). It carries an
explicit note: reachability is import-level β a domain can be reachable yet
run degraded (e.g. optional numpy missing). Nothing is masked green.
HTTP API
Mounted onto the operator's Flask app by register_saas_routes(app), so one
service on port 8790 serves operator + cognition + the SaaS catalog behind the
same security envelope (bearer auth / rate-limit / metrics / health from
PRODUCTION_GRADE.md).
| Method | Route | Returns |
|---|---|---|
GET |
/api/catalog |
Categorized catalog (12 categories Γ domains Γ systems). |
GET |
/api/domains |
Product domains + per-domain reachability report. |
GET |
/api/domains/<domain> |
One domain: entry point + its systems (capped). |
GET |
/api/status |
Live platform health (honest, often degraded). |
GET |
/api/organism |
Connectome coverage + recent breaths + mesh membership + unification telemetry. |
GET |
/api/cognition |
The whole cognitive substrate + data provenance + truth roll-up. See architecture/COGNITIVE_SAAS.md. |
GET |
/api/cognition/<part> |
One cognitive surface: field Β· bus Β· mycelium Β· connectome Β· brain, each provenance-stamped. |
GET |
/api/consciousness |
The consciousness organs, categorized (self-perception Β· selfhood Β· purpose Β· governance Β· workforce Β· body), each with its route, safety posture & live truth_status. See architecture/CONSCIOUSNESS_CATALOG.md. |
GET |
/api/automation |
Progress toward "the whole repo, fully automated" β one honest % decomposed by dimension (connectivity Β· integration Β· consciousness Β· surfacing) + by category, composed from real coverage only. See architecture/AUTOMATION_INDEX.md. |
GET |
/api/manifests/<name> |
A frontend manifest, rendered live (404 lists available names). |
POST |
/api/manifests/refresh |
Rebuild the catalog; static files rewritten only with AUREON_WRITE_STATIC_MANIFESTS=1. |
Tenancy bridge (optional, off by default)
The Supabase backend already owns auth/RBAC/billing. The gateway bridges to it
without a new dependency: when AUREON_SUPABASE_JWT_SECRET is set, the
/api/* routes additionally require a valid Supabase JWT, verified with a
stdlib HS256 check (verify_supabase_jwt β signature + exp). The verified
sub (user id) is stashed on flask.g.tenant for downstream scoping.
When the secret is unset the bridge is disabled (dev/offline unchanged), layered on top of the operator's own bearer/rate-limit envelope β the two are independent gates.
βββββββββββββββββββββββββββββββββββββββββββ
React console ββJWTβββΊβ operator service :8790 β
(Supabase session) β β security envelope (bearer/rate-limit) β
β β [optional] Supabase JWT bridge β
β β operator + cognition routes β
β β SaaS routes β catalog/domains/status ββββΊ the 715-module
βββββββββββββββββββββββββββββββββββββββββββ Python organism
(surfaced, not rewritten)
Verify
pip install -e '.[operator,dev]'
ruff check aureon/saas/ && mypy aureon/saas/
AUREON_LLM_OFFLINE=1 pytest tests/test_saas_catalog.py tests/test_saas_gateway.py -q
# catalog + manifests
AUREON_LLM_OFFLINE=1 python -c "from aureon.saas.catalog import build_catalog, write_frontend_manifests; c=build_catalog(); print('categories', c['category_count'], 'systems', c['total_systems']); print('manifests', [p.split('/')[-1] for p in write_frontend_manifests()])"
# gateway routes (offline)
AUREON_LLM_OFFLINE=1 python -c "from aureon.operator.operator_server import create_app; c=create_app().test_client(); print('catalog', c.get('/api/catalog').status_code, 'status', c.get('/api/status').status_code, 'domains', len(c.get('/api/domains').get_json()['domains']))"
CI gates on aureon/saas in the strict tier (operator-ci.yml): ruff-clean +
mypy-clean + tests/test_saas_*.py green.
Runtime and deployment status
The SaaS implementation is source-visible and testable offline, but runtime and
deployment are on terminal HOLD. deploy/docker-compose.saas.yml starts only
non-networked protection preflights. The frontend image performs no package
lifecycle or source build, starts no nginx listener, and exposes no port.
Frontend dev, preview, E2E, trading, and runtime package scripts are held.
Do not inject tenant, Supabase, operator, model, or hosting credentials merely to verify this source. No console, gateway, manifest route, tenancy service, or payment route is deployed by the supported entrypoints.
Billing (Phase 6C)
The authority boundary first: the platform never initiates payments. Metering is record-only; the single money-moving route ships disabled and is audited.
Three layers, all reusing the wallet that already existed
(gas_tank_accounts + gas_tank_transactions, the Β£-denominated performance-fee
tank with its working gas-tank-topup edge function):
1. Support the project (money in β the user's choice, on their clock)
Aureon runs free. The console tracks cumulative runtime locally and, after ~4
hours of use, shows a small dismissible corner card β never a modal, never a
gate β inviting the user to support the project via the SumUp payment links
(VITE_SUPPORT_PAYMENT_URLS; defaults are the project's live links). The flow
is self-confirmed: the user says what they gave, the existing
gas-tank-topup edge function credits their tank, and a payment_transactions
row (provider: sumup, status: self_confirmed) is recorded so payouts can be
reconciled manually against SumUp. Trust-based by design; the admin
verify-payment flow remains for disputes.
2. Usage metering (record-only β aureon/saas/metering.py)
When AUREON_BILLING_METERING=1, every /api/* request becomes one
api_request event (tenant-attributed via the Supabase JWT when present) in a
bounded buffer, flushed by a daemon thread to the saas_usage_events table via
PostgREST. Per-provider LLM token usage β parsed by the operator all along but
previously dropped β is swept into llm_tokens events and the
aureon_llm_tokens_total Prometheus counter. Honesty rules: drop-oldest is
counted, flush failures are counted and dropped, and GET /api/billing/status
names the true sink (disabled / prometheus-only / supabase). Nothing in
this layer debits a balance. Per-tenant token attribution is staged (fan-out
runs in worker threads; claiming it now would be dishonest).
3. Billing API + the fee path's first caller (aureon/saas/billing.py)
| Method | Route | Returns |
|---|---|---|
GET |
/api/billing/status |
Always 200: config, metering stats, token totals, flags. |
GET |
/api/billing/balance |
The tenant's gas-tank account (503/401/404/502 β precise, never a bare 500). |
GET |
/api/billing/usage |
The tenant's usage events + buffer stats. |
POST |
/api/billing/charge-fee |
β MOVES MONEY β ships OFF. 403 unless AUREON_BILLING_CHARGE_ENABLED=1. |
charge-fee is the first-ever caller for the previously dead
gas-tank-deduct-fee edge function (the performance-fee math β 20%/10% on
profit above the high-water mark β stays there, single source of truth). It
exists for the server-side trade loop: the profit-realization step POSTs
{user_id, profit, trade_execution_id} behind the operator bearer, and every
attempt is audited as a fee_charge usage event. No live trader is wired to it
yet β that hookup is a deliberate, separate decision.
Billing environment
| Var | Default | Effect |
|---|---|---|
SUPABASE_URL / SUPABASE_SERVICE_ROLE_KEY |
unset | PostgREST + edge-function access |
AUREON_BILLING_METERING |
off | usage-event recording/flushing |
AUREON_BILLING_FLUSH_S / _BUFFER_MAX / _HTTP_TIMEOUT_S |
10 / 5000 / 5 | tuning |
AUREON_BILLING_CHARGE_ENABLED |
off β moves money | enables charge-fee |
VITE_SUPPORT_PAYMENT_URLS |
the project's SumUp links | support links |
VITE_SUPPORT_PROMPT_HOURS / VITE_SUPPORT_SNOOZE_HOURS |
4 / 12 | prompt cadence |
Hardening notes (recorded, not yet fixed)
gas_tank_accounts.fees_paid_todayis never reset by any job.payment_transactions.currencydefaults to'EUR'in the schema while every writer sends'GBP'.- Several older tables use permissive
USING(true)RLS write policies (service-role reliance);saas_usage_eventsdeliberately does not. REFUND/ADJUSTMENTtransaction types are declared but never produced.aureon_user_sessions.gas_tank_balanceis vestigial β overloaded as "harvested capital", unrelated to the wallet.- When the operator bearer (
AUREON_OPERATOR_API_KEY) and the Supabase JWT bridge are both enabled they compete for the sameAuthorizationheader.
Unified UI Shell (Phase 7)
One professional interface for the entire repo β every capability behind one sidebar, one router, one design language (the Aureon prism identity, kept by the creator's choice).
Architecture: the shell wraps the monolith, it does not rewrite it.
frontend/src/shell/nav.tsβ the single source of truth: sections β routes β icons β lazy page loaders. The sidebar, router, breadcrumbs, and command palette all derive from this table; adding a surface is one entry.ShellLayout.tsxβ collapsible grouped sidebar (built on the previously unused shadcnui/sidebar.tsx+ existing--sidebar-*tokens), top bar with breadcrumb, live platform-status dot (pollsGET /api/status), and a βK command palette that jumps to any surface.- Routes (all
React.lazyβ every surface is its own chunk): Trading war-room Β· live bridge Β· Orca Β· analytics Β· backtesting β Research & Planetary Harmonic Nexus Β· Earth resonance Β· solar Β· NOAA space weather β Cognition & LLM Operator Chat (new: talks to/api/cognition/reason, renders grounding sources, tool calls, and the conscience verdict honestly) Β· agent company β Coding System organism Β· skills Β· work orders Β· director bridge β Operations gold & capital Β· systems integration Β· operational console β Platform overview (new) Β· repo map Β· billing & support (new) Β· legacy console. - The legacy nine-tab console is preserved intact at
/platform/console(exported asLegacyConsolefromApp.tsx); its five entangled tabs (live-ops, trading audits, security, inventory, evidence) still work, and old#tabdeep links redirect into the right shell route. - Resilience: every route renders inside a per-route error boundary (a crashing dashboard never takes down the shell) with a retry, and live-data surfaces carry an honest notice when no backend is connected.
- Performance:
vitemanualChunks + route-level lazy loading split the former 1,566 kB single bundle into a 227 kB entry + per-surface chunks; the oversize-chunk warning is gone.
Historical UI builds and smoke tests are implementation evidence only. The current release image deliberately performs no frontend build and starts no browser-facing listener.
Staged ledger
The implementation ledger below separates source work from runtime release:
| # | Phase | Item | Done? |
|---|---|---|---|
| 6A | Platform layer | Categorized catalog + domain adapters + honest status + gateway routes + Supabase JWT bridge. | β |
| 6B | Frontend release | Historical nginx/compose design is retained in source history; active image and package routes are terminal HOLD and build/start nothing. | HOLD |
| 6C | Billing | Support-the-project flow (SumUp, self-confirm β gas tank) + record-only usage metering + billing read API + env-gated charge-fee proxy. Staged: per-unit debits, per-tenant token attribution, automated payment capture (SumUp API/Stripe), trade-loop fee hookup, usage panel UI. | β |
| 7 | Unified UI shell | Router + grouped sidebar + command palette over every surface; new Overview/Operator-Chat/Billing pages; legacy console preserved; per-route error boundaries; code-split bundle. Staged: extracting the legacy console's five entangled tabs into shell routes. | β |
| 9 | Organism connectome | Source and tests cover sense/touch/weave/pulse and related APIs. Supervisor routes remain terminal HOLD; no dormant organ or HNC daemon is started. | SOURCE ONLY |
| 10 | Investor-ready repo | Professional README (hero + badges + staged registers), COMPANY.md with real credentials (Companies House NI696693, Silver Innovate NI cert), root health files + templates, de-cluttered root (binaries/junk/launchers/standalone scripts relocated with history preserved). Secret hygiene: removed a tracked .env1.txt. |
β |
| 22 | Cognitive Systems SaaS | The cognitive + meta-cognitive substrate (field Β· bus Β· mycelium Β· connectome Β· brain) as verified read APIs at /api/cognition*, each response provenance-stamped (live/real_derived/cached_real/no_data, never fabricated); auto-metered + auth-gated; console page at /cognition/systems. No cold-boot of heavy organs from a GET. See architecture/COGNITIVE_SAAS.md. |
β |
| 39 | Consciousness catalog | The Phase 25-38 consciousness organs categorized into one honest surface β self-perception Β· selfhood Β· purpose Β· governance Β· workforce Β· body β each with its purpose, route, safety posture (read_only_assess / records_only_gated / reversible_ascent_gated) and live truth_status. Registry-as-data at /api/consciousness; Consciousness page at /cognition/consciousness. Dormant organ β no_data, never fabricated. See architecture/CONSCIOUSNESS_CATALOG.md. |
β |
| 41 | Automation progress index | One honest % toward "the whole repo, fully automated", decomposed by dimension (connectivity Β· integration Β· consciousness Β· surfacing, weight-renormalized) + by category, composed from real coverage signals only (clamped; dormant β index_pct: null + no_data, never inflated). /api/automation; headline card on Overview; observational only. See architecture/AUTOMATION_INDEX.md. |
β |
| 54 | Feature switchboard | Turn every system feature on/off at human discretion β instance-owned, encrypted flag store (~/.aureon/feature_flags.json.enc), applied at daemon boot via bootstrap_credentials(). Safe toggles + a hard-boundary tier behind a typed-confirm arming ceremony. Flipping only sets the flag's own env var β no downstream gate (conscience veto / approval queue / runtime dry-run) is ever removed. /api/switchboard; Switchboard page at /platform/switchboard. See architecture/FEATURE_SWITCHBOARD.md. |
β |
Guardrails
The operator security envelope is reused; the Supabase JWT bridge is off by
default; hard authority boundaries (live-trade / payment / credential / filing)
and the AUREON_LLM_OFFLINE / AUREON_AUDIT_MODE guards stay in force. The 715
modules are surfaced and health-checked, not rewritten. Status is honest.
state/ caches and frontend/public/ manifests are generated and gitignored.
The Supabase project and its secrets are untouched (read-only bridge).
π Related
runbooks/PRODUCTION_GRADE.mdΒ·architecture/AUREON_OPERATOR_SWITCHBOARD.mdΒ·deployment/OPERATOR_DEPLOY.mdMODULES_AT_A_GLANCE.mdβ the 24 filesystem domainsaureon/saas/Β·.github/workflows/operator-ci.yml
π The organism, made legible: every system categorized, every domain connected, every status honest.