Repositories openvibers openvibe.space official
openvibers/openvibe.space
Open source forum and member spaces: moderators, threads, reactions, votes and a Discord relay.
Get it
Get this repository
A Git token is made for this copy and shown once. It can read and write the repositories you own, and expires in an hour.
git clone https://git.openvibe.codes/openvibers/openvibe.space.git
OpenVibe Link asks you on your computer. The folder is inside the root you chose in Link, and the request ends after two minutes.
Clone to my computerA Codes session clones from our disk: no network, no GitHub quota. When this repository has a GitHub twin, Codes pushes there too.
Open in CodesREADME.md
View fileOpenVibe.Space
https://openvibe.space — spaces (apps people make on their OpenVibe account) and static hosting for the OpenVibe network.
Live site: https://openvibe.space · API docs: https://openvibe.services · For AI: https://openvibe.space/llms.txt
Run it: npm ci && npm run dev (Node 22 or newer) · Tests: npm test
Purpose and status
Space owns static hosting. The Stage B engine moved here from OpenVibe.Host as code; production had no projects, sites or deploys to migrate. It supports projects and members, immutable content-addressed deploys, activation and one-step rollback, private previews, CI Git ingest, per-site configuration, verified custom domains, takedowns, Media-backed objects, Host-header tenant serving, and a resource index. Tenant names serve at <name>.openvibe.website.
Public hosting remains off by default (SPACE_PUBLIC_HOSTING=off). Only OpenVibe staff can create projects. Abuse handling and a designated DMCA agent precede public launch.
Spaces (plan T20 step 2; server/spaces/, docs/spaces.md) are small web apps people make here: described to the AI
builder (OpenVibe.AI space.app.build), started from a template (guestbook, AI buddy, poll, reaction game, trivia,
private to-dos, blank) or forked, then edited in a browser editor with a live preview. A space uses the visitor's
OpenVibe account through the space SDK (/_openvibe/sdk.js): sign-in that the visitor approves once, shared lists
(OV.items), private storage (OV.kv), the space's own AI (OV.ai.ask, OpenVibe.AI space.app.ask on behalf of
the visitor) and its own server code (functions/<name>.js, run in a QuickJS WebAssembly sandbox at /api/<name>
and from OV.fn). Making, editing, previewing and the AI builder work for everyone signed in. Publishing deploys a space to
a site of its maker's Spaces project at <slug>.openvibe.website, so it follows the same launch switch: staff until
SPACE_PUBLIC_HOSTING=on.
OpenVibe.Host is the hosting price comparison; its copy of the engine is being removed, and its old hosting URLs will answer 410 with a link here.
Owns
- Spaces: their source files and settings, the gallery, the editor, the space SDK and its API, each space's shared lists,
its visitors' private storage, the sign-ins visitors approved, and the daily AI allowances of spaces and builders. - Static hosting: projects and members, sites, immutable content-addressed deploys, activation and rollback,
previews, Git ingest, per-site configuration, custom domains with TXT verification, and takedowns. - Serving tenant sites by Host header at
<name>.openvibe.websiteand on verified custom domains. - Its tables in
ov_space(space_*), its control log and its outbox (space.deploy.*,space.domain.verified).
Does not own
- People, sessions and projects' identity (OpenVibe.Network), stored bytes when
SPACE_OBJECT_STORE=media
(OpenVibe.Media), money and usage rating (OpenVibe.Billing), the forum (OpenVibe.Community, see below) and the
hosting price comparison (OpenVibe.Host).
Depends on
- OpenVibe.Network: sign-in (OAuth with PKCE), tokens and their keys, project membership.
- OpenVibe.Events: the outbox relay, when
EVENTS_URLis set, and account export and deletion (ADR-033):
network.account.export_requestedandnetwork.account.deletedreach the loopback/internal/eventsconsumer
(server/account-data.js, openvibe-sdk/account-data), signed withSPACE_EVENTS_SECRET. A person's spaces are
exported with their files; on deletion their published spaces stop serving and the spaces go with what others kept
in them, and their list items, private storage and sign-ins leave other people's spaces. - OpenVibe.Media: tenant objects, when
SPACE_OBJECT_STORE=media. - OpenVibe.Billing: storage readings, when
SPACE_BILLING_INTERVAL_MSis on. - OpenVibe.Services: reads the resource index and sends control requests.
- OpenVibe.AI: the space builder and a space's own AI (
space.*workflows; Network grantsai.run.createand
ai.run.readonspace.*).
The forum moved to OpenVibe.Community
The forum lived here from 3 October 2026 (it moved off Community then). On 2026-10-08 the owner
moved it back: OpenVibe.Community owns the forum (spaces, threads, posts, votes, categories,
per-space moderators, the Discord relay) again, and Space became the network's hosting (static sites now; dynamic pages and spaces next).
So Space keeps no forum code and **every forum URL answers a permanent redirect to the forum's
address on https://openvibe.community** (which moved from /s to /forum on 2026-11-07):
| Path | Methods | Status | Goes to |
| --- | --- | --- | --- |
| /s, /s/* (pages, feeds) | GET, HEAD | 301 | /forum/<space>/<thread> (the /t/ segment is gone) |
| /s, /s/* | anything else | 308 (the method and body are preserved) | the same /forum path |
| /api/v1/spaces*, /api/v1/posts/*, /api/v1/space-groups*, /api/v1/relay* | all | 308 | the same API path |
A redirected bookmark, crawler or API client therefore lands on Community's copy in one hop.
Nothing that is not a forum path redirects.
Routes
| Route | Purpose |
| --- | --- |
| / | Spaces and static hosting |
| /spaces, /spaces/new, /spaces/mine, /spaces/:slug | The gallery and templates, making a space (template or AI builder), your spaces, a space's page |
| /spaces/:slug/edit and its JSON calls (files, settings, ai, publish, unpublish, delete, preview) | The editor (maker or staff; same origin with the form token in X-CSRF-Token) |
| /spaces/:slug/fork, /spaces/:slug/connect | Fork a space; the sign-in a visitor approves for a published space |
| /_openvibe/sdk.js | The space SDK: live on a space's own address, preview mode on openvibe.space |
| /api/v1/apps/:id/token, /api/v1/apps/:id/run, /api/v1/apps/:id/items/:collection | The space SDK's API, from the space's own origin only (CORS for that origin, Bearer space token, never cookies) |
| /dashboard, /projects/:id, /sites/:id, /deploys/:id | Signed-in hosting dashboard and forms |
| /preview/:deployId/* | Private, sandboxed deploy preview |
| /api/v1/projects, /api/v1/sites, /api/v1/deploys, /api/v1/domains | Hosting API (Bearer tokens, no cookie auth) |
| /api/v1/resources | First-party resource index |
| POST /api/v1/resources/control | First-party control: delete a site, deploy or domain for a person (Space's own roles decide) |
| /limits.json | Enforced hosting limits |
| /auth/login|callback|fedcm|logout|me|refresh | Space's Network OAuth client |
| /robots.txt, /llms.txt, /llms-full.txt, /sitemap.xml | Discovery for Space's public page |
| /api/health, /api/ready, /release.json, /metrics | Health, release and observability |
Sitemap entries carry lastmod from the release commit or, for hosted pages, the active deploy.
Tenant requests are dispatched by Host header before dashboard routes. deploy/nginx/openvibe.website.conf is a reference wildcard vhost; the existing openvibe.space vhost includes larger upload locations. Neither is installed by this code change. Unknown hosts answer 404. Tenant sites cannot reach the dashboard, API, auth or metrics. A custom domain serves only after TXT verification.
Capabilities and events
The hosting API guards space.site.manage, space.site.config, space.deploy.create, space.domain.manage, space.resource.read and space.resource.control (openvibe-contracts 0.170.0, owner space); every route names exactly one, and npx openvibe-contracts-check --service space checks the code against the release. Service tokens need audience openvibe.space, and project membership still applies. The per-actor limits (server/http/actor-limits.js) count uploads, domain checks, project creation and writes per person or app; those are limit buckets, not capabilities. The retired space.forum.* contracts are unrelated to hosting. The control route (server/registry/resource-control.js, plan T13 step 10) takes a common.resource-control-request@1 from OpenVibe.Services and acts as the person in on_behalf_of through the same domain code as the DELETE routes: deleting needs maintainer or owner, a non-member gets resources.unknown_resource, and the served deploy (deploy.active), a default domain (domain.default) and anything taken down are refused with Space's own reason. Dry runs; repeats with the same key return the first answer (space_control_log).
The transactional outbox emits space.deploy.created, space.deploy.activated, space.deploy.failed and space.domain.verified; each has a payload schema in openvibe-contracts, and the SDK outbox refuses any other type.
Data and configuration
migrations/0002_initial.sql through 0005_git_sources.sql create the hosting tables, 0006_billing_readings.sql the usage-reading outbox,, indexes and immutable-artifact triggers from Host Stage B with space_ names. They run through openvibe-sdk/db at boot; tables are never created by a request. 0001_initial.sql remains the historical forum schema, which this release does not drop. This is a code move, with no data copy.
migrations/0009_spaces.sql creates the spaces tables (space_apps, space_app_files, space_app_projects, space_app_items, space_app_kv, space_app_grants, space_app_codes, space_app_tokens, space_app_counters). Only hashes of sign-in codes and tokens are kept.
migrations/0010_account_data.sql creates openvibe-sdk/account-data's account_data_events (the forum-era table of that name is kept as account_data_events_forum).
Request telemetry is aggregated by route template, method and status class, never by raw URL. Once a minute one http.request sample per key, plus the active-requests, p95 latency and event-loop-lag gauges, is written to this service's own telemetry_samples table (openvibe-sdk 0.46 telemetry, the platform.telemetry-sample@1 shape), which migrations/0008_telemetry.sql creates; rows older than 14 days are deleted daily. /shared files, static assets, health, readiness and /metrics are not counted. server/app.js mounts openvibe-sdk's telemetryMiddleware (a no-op until init); server/index.js calls telemetry.init() at production start, runs the 14-day retention and flushes on stop.
Copy .env.example to .env. Production uses /etc/openvibe/space.env (0600). Important values:
| Variable | Default | Purpose |
| --- | --- | --- |
| SPACE_PUBLIC_HOSTING | off | Staff-only project creation (and publishing spaces) until launch |
| SPACE_EVENTS_SECRET | unset | Signs OpenVibe.Events deliveries to /internal/events (account export and deletion); unset answers 503 |
| SPACE_AI, OV_AI_INTERNAL_URL | on, http://127.0.0.1:4700 | The space builder and spaces' AI through OpenVibe.AI |
| SPACE_SPACES_PER_OWNER, SPACE_AI_BUILDS_PER_DAY, SPACE_AI_ASKS_PER_SPACE_PER_DAY | 25, 20, 500 | Spaces per person, AI builds per person a day, AI answers per space a day (more SPACE_SPACE_* limits in server/hosting-config.js) |
| SPACE_SITES_DOMAIN | openvibe.website | Tenant names |
| SPACE_STORAGE_DIR | ./data/objects | Content-addressed local object store |
| SPACE_OBJECT_STORE | local | Set media for Media write-through and cache |
| SPACE_FORM_SECRET | random per process | Dashboard CSRF form signing |
| SPACE_WORKER | on | Domain rechecks, object sweep, outbox pruning |
| EVENTS_URL | unset | Outbox relay destination; unset keeps rows queued |
| SPACE_BILLING_INTERVAL_MS | 0 (off) | Daily gb-month storage readings to OpenVibe.Billing (OV_BILLING_URL) in local mode, per OpenVibe.Network project (network_project_id; a project that names none gets no reading); Media mode emits none (Media bills the bytes) |
| DATABASE_URL, DATABASE_DIRECT_URL | unset | PostgreSQL serving and owner migration connections |
Other SPACE_* quota, upload, domain and DNS settings are listed in .env.example and server/hosting-config.js. Space keeps its existing OAuth and forum redirect settings.
Tests and running
npm install
npm start
npm test
test/hosting-core.test.js exercises migrations, launch gate, project/site creation, tenant dispatch, immutable deploys, pointer rollback and events directly against PGlite without a socket. The ported Stage B integration files under test/hosting-*.test.js use test/stageb/boot.js and raw HTTP for Host-header and request-target cases. The existing home, redirects, and boot tests cover Space's public app and forum redirects.
Security and dependencies
Static uploads are validated before storage; tenant content runs on a separate registrable domain and previews use a sandbox CSP. APIs ignore cookies. OpenVibe.Network supplies identity; svc:space needs events.event.publish, billing.usage.record (audience openvibe.billing) once SPACE_BILLING_INTERVAL_MS is on, and, when SPACE_OBJECT_STORE=media, the media.object.upload/read/list/delete grants for the space namespace. OpenVibe.Media may hold tenant objects; OpenVibe.Events receives the outbox when configured. Space's own database is ov_space through openvibe-sdk/db. See [SECURITY.md](SECURITY.md).
Deploy
sudo ovhost deploy space on the host: the release layout under /opt/openvibe.space, /etc/openvibe/space.env, the
openvibe-space unit, migrations at boot. The vhosts are deploy/nginx/ (installed with ov-vhost-install).
License
AGPL-3.0-only. See [LICENSE](LICENSE).
<!-- versions:start -->
- openvibe-contracts: v0.419.0
- openvibe-sdk: v0.161.0
- openvibe-shared: v4.234.0
<!-- versions:end -->