Packaging a release
A Paracosm release is one folder, made by one command, build/make_release.py (below). Building the server from
the source (quickstart.md section 4) is the primary path: it is the only one on Linux and macOS,
and the one for anyone who changes the source. For Windows x64 the release also carries a prebuilt server, built
from the release's own source zip and never started, so it holds no config, region UUID or token: each install
makes its own with tools/make_config.py.
| part | made by | file |
|---|---|---|
| the source | git archive of the release commit |
paracosm-src-<version>.zip |
| the server, prebuilt (Windows x64) | build/build_server.py, run on that source zip |
paracosm-server-<version>-win64.zip |
| the viewer, portable (Windows x64) | viewer-build/package.py |
Firestorm-Paracosm-<version>-win64-portable.zip |
| worlds (optional) | tools/backup.py, its region.oar only |
worlds/starter-island.oar, worlds/paracosm-island.oar |
| the notes and sums | build/make_release.py |
RELEASE-NOTES.md, SHA256SUMS.txt |
The release version is the one line in VERSION at the repository root (1.0.0).
Making a release: build/make_release.py
Commit everything first: the release is HEAD as committed. Then, from the repository root:
python build/make_release.py --sqlite3-dll PATH/sqlite3.dll [--starter-oar PATH] [--island-oar PATH]
It writes <the repository's parent>/paracosm-release/<version>/ (or --out DIR, which must be outside the
repository) and refuses a folder that is not empty unless --clean. It prints PASS or FAIL for every check, a
table of the files (size, SHA-256 prefix) at the end, and exits 1 on any failure. A failure in the source stops
the run before anything is built from it. The server build takes several minutes (dotnet at idle priority).
| option | does |
|---|---|
--out DIR |
the release folder (default <repo parent>/paracosm-release/<version>) |
--clean |
delete a non-empty --out, and a work folder a failed run left, first |
--sqlite3-dll PATH / --sqlite3-zip PATH / --fetch-sqlite3 |
the official SQLite DLL for the server build, passed to build_server.py (hash-checked there); one is required unless --skip-server |
--opensim-zip PATH |
opensim-0.9.3.0-source.zip (default: the repository root, or the main checkout of a git worktree) |
--dotnet PATH |
a dotnet other than the one on PATH |
--work DIR, --keep-work |
the server build's work folder (default <out's parent>/.work-<version>), removed after a good run unless --keep-work; kept after a failure |
--skip-server |
no prebuilt server in this release |
--viewer-zip PATH / --no-viewer |
the viewer package to copy (default: the newest Firestorm-Paracosm-*-win64-portable.zip in $FS_ROOT/paracosm-package, FS_ROOT defaulting to C:/fs) / none. With no package there, it says so and carries on |
--starter-oar PATH, --island-oar PATH |
copied in as worlds/starter-island.oar and worlds/paracosm-island.oar |
--secrets-env PATH |
also refuse any password, token or secret value (8 characters or more, not change-me...) from this env file found in the zips' text files. Use it with your own .env |
What it does and checks:
| part | how it is made | checks (each one a PASS/FAIL line) |
|---|---|---|
| source | git archive --format=zip --prefix=paracosm-<version>/ of HEAD |
nothing from "Never in a release" below; in every text file no retired demo value (the old WorldBridge demo token and two early default passwords, compared by SHA-256 so the script does not carry them), no PEM or PuTTY private key block, no AWS, GitHub, Anthropic, Slack or Google credential; the files a release needs are there; build/source-commit names HEAD; VERSION is the version; the zip reads back |
| server | the source zip unpacked into the work folder, then that copy's build/build_server.py <work>/server --low-priority with the given SQLite DLL, no --env, and no PARACOSM_*/WORLDBRIDGE_* variables from the calling shell, so step 9 (config) is skipped |
the build exits 0; the manifest names this commit and version and records no config; the never-list again (the per-install config files included), so no config, token, database or log is in it: it was never started; OpenSim.dll and WorldBridge.dll in the zip match the manifest and sqlite3.dll the pinned hash; the same text scan; the zip reads back |
| viewer | copied | one Firestorm-Paracosm/ folder with FirestormOS-Paracosm.exe and its licence files; no Vivox binaries; its source/viewer-patches/ (the LGPL source offer) byte-identical to the source zip's viewer-patches/; the zip reads back |
| worlds | copied | each is a gzip'd tar holding archive.xml |
| notes and sums | written last, RELEASE-NOTES.md first so the sums cover it |
SHA256SUMS.txt (LF lines, <sha256> <file>) reads back and matches every file, as sha256sum -c does |
The demo token is public (it shipped in the source) and every WorldBridge since the fail-closed change refuses
it, so it may stay in the files that refuse or document it and in the early scenes/ scripts that still send it
(handbook/README.md); the script lists them, and it anywhere else is a failure. The two versioned files under
assets/ (assets/firestorm-ref-skin.json, assets/boulders/originals.json) are allowed; anything else there is
not.
The server zip holds one folder, paracosm-server-<version>/:
| path | what |
|---|---|
README-SERVER.txt |
what the server is and the three steps to configure and start it: .env from .env.example (with PARACOSM_BIN set to this bin/), tools/make_config.py <bin>, tools/run_server.py start, all run from the unpacked source zip |
bin/ |
the runnable server, exactly as the build left it |
paracosm-build.json |
the build manifest (below), with the commit read from the source zip's build/source-commit |
licenses/ |
OpenSimulator's LICENSE.txt, CONTRIBUTORS.txt and ThirdPartyLicenses/, and this repository's LICENSE and NOTICE.md (a binary redistribution must carry the BSD notices) |
The source by hand
make_release.py does this for you. By hand, ship an export of one commit, not the repository:
git archive --format=zip --prefix=paracosm/ -o ../paracosm-src.zip HEAD
git archive writes the tracked files of that commit and no history. The history still holds retired demo values
(the old WorldBridge demo token and earlier default passwords), so it is not published. Everything git ignores
stays out by construction: .env, backups/, assets/, opensim-src/, *.zip, *.db, *.log, *.bak.
build/source-commit is marked export-subst in .gitattributes, so the export holds the commit's hash there, and
a server built from the export records it in paracosm-build.json.
The export carries the OpenSim patches (opensim-patches/), WorldBridge, the MCP server, the tools, the config
templates, the build and run scripts, the viewer patches and build scripts (the LGPL source for the viewer, against
the base commit named in viewer-patches/README.md), the handbook, LICENSE, NOTICE.md and .env.example.
Before exporting, check that no value from your own .env is tracked: for each password or token,
git grep -n -F "<value>" must print nothing.
The portable viewer zip (Windows x64)
Prerequisites
| tool | version used for the reference package |
|---|---|
| Visual Studio 2022 Build Tools (C++ workload, ATL, a Windows SDK) | MSVC 14.44.35207 |
| CMake | 4.3.4 |
| Git for Windows | (its bash and GNU patch are used by Firestorm's configure script) |
| Python | 3.12.10, with pip install -r requirements.txt from the Firestorm tree |
| autobuild | 3.10.3.dev9 (pip install git+https://github.com/secondlife/autobuild.git) |
| llbase | 1.3.1 |
| fs-build-variables | commit c17312d3 |
Not needed: FMOD, Havok, KDU (nothing licensed), NSIS (the package is a zip, not an installer).
Steps
The scripts default to the folder C:\fs; set FS_ROOT (and VCVARS, PY_SCRIPTS, see
viewer-build/configure.bat) if yours differ.
-
Get the pinned sources and apply the ten patches (
viewer-patches/README.md):cd /d C:\fs git clone https://github.com/FirestormViewer/phoenix-firestorm.git git clone https://github.com/FirestormViewer/fs-build-variables.git git -C fs-build-variables checkout c17312d3 cd phoenix-firestorm git checkout -b paracosm 3125052b git am C:/paracosm/viewer-patches/00*.patch -
Configure:
C:\paracosm\viewer-build\configure.bat(autobuild with--opensim --chan ParacosmandLL_TESTS=FALSE). It ends withCONFIGURE_EXIT=0. -
Build:
C:\paracosm\viewer-build\build.bat(msbuild directly, at low priority). It ends withBUILD_EXIT=0. A first build takes about half an hour. -
Package:
python C:/paracosm/viewer-build/package.py [--out C:/fs/paracosm-package]It runs Firestorm's own
viewer_manifest.pywith thecopy packageactions into<out>/Firestorm-Paracosm/, which lays out a runnable viewer (the exe with itsapp_settings,character,fonts,skinsand plugins). The manifest's last step builds an NSIS installer and fails without NSIS; the script says so and carries on, because the staging is complete by then. It then removes the Vivox voice binaries (SLVoice.exe,vivoxsdk_x64.dll,ortp_x64.dll,VivoxAUP.txt) and the installer script, adds the licence files and the patch source (below), writesREADME-FIRST.txt, and zips the folder as<out>/Firestorm-Paracosm-<version>-win64-portable.zip(the version from the build'sviewer_version.txt).
The reference package is Firestorm-Paracosm-7.2.5.1-win64-portable.zip, 341 MB. The zip holds one folder,
Firestorm-Paracosm/, whose FirestormOS-Paracosm.exe runs from wherever it is unzipped. Its launch on a clean
Windows account has not been checked yet.
Licences in the viewer package
The viewer is LGPL 2.1. Firestorm-Paracosm/ in the zip carries:
| file | from |
|---|---|
licenses.txt |
the third-party libraries (written by Firestorm's manifest) |
LGPL-license.txt |
<FS_ROOT>/phoenix-firestorm/doc/LGPL-license.txt: the viewer's licence |
LICENSE-logos.txt |
<FS_ROOT>/phoenix-firestorm/doc/LICENSE-logos.txt: the Linden Lab artwork notice |
Paracosm-LICENSE.txt, Paracosm-NOTICE.md |
this repository's LICENSE (BSD-3, our own code, not the viewer) and NOTICE.md |
source/viewer-patches/ |
every viewer-patches/*.patch and its README.md (upstream URL, base commit, apply order) |
README-FIRST.txt |
written by package.py; names the upstream repository, the base commit (read from viewer-patches/README.md) and the files above |
package.py stops before running the manifest if either Firestorm licence file, LICENSE, NOTICE.md or the
patches are missing. The source offer is the patch series in the zip plus the upstream base commit; the full
source export above carries the same patches. Firestorm-Paracosm is a downstream modified build, not an official
Firestorm release (NOTICE.md).
macOS and Linux viewer builds are not made or documented here; Firestorm's own doc/building_*.md cover them.
The server build output
build/build_server.py <out> leaves:
| path | what |
|---|---|
<out>/bin/ |
the runnable server: OpenSim, the patched DLLs, sqlite3.dll (Windows), WorldBridge.dll |
<out>/bin/OpenSim.ini, config-include/StandaloneCommon.ini, config-include/FlotsamCache.ini, config-include/osslEnable.ini, Regions/Regions.ini |
the config, written from the env file (only when there was one) |
<out>/paracosm-build.json |
the manifest: repository commit (from git in a checkout, from build/source-commit in an export), the version in VERSION, zip hash, each patch and patched file's hash, the SQLite DLL's source (a download's URL, a local file's name) and hash, the hashes of OpenSim.dll and WorldBridge.dll, the config files written, the build host |
<out>/.paracosm-build/worldbridge/ |
WorldBridge's build folder |
everything else in <out> |
the patched OpenSim source tree it was built from |
A bin/ is per-install once it has config or has run. A prebuilt server is built from a fresh source export that
has no .env (the config step is then skipped and prints the command to run later) and is never started before
shipping; make_release.py does exactly that and checks the result. Ship bin/ with none of the items below.
The docs as web pages
The docs are also published as plain web pages beside the Paracosm page (neap.systems/paracosm/docs/), so they
can be read without downloading a release. From the repository root:
python build/make_docs_site.py [OUT_DIR]
python build/check_docs_site.py [OUT_DIR]
OUT_DIR defaults to build/out/docs (git-ignored). make_docs_site.py needs markdown-it-py (in
requirements.txt, used by nothing else). It renders the root README.md as the docs home, with the handbook's
contents listed under it, then the handbook in the order of its contents page, the MCP server's, WorldBridge's, the
viewer patches' and each OpenSimulator patch's notes, and NOTICE.md; plan_docs() in the script is the list, and
it prints what it made and what it left out. A link to another rendered doc becomes a link to its page (headings
get GitHub's ids, so #anchors carry over); a link to any other file in the repository is shown as its path in code
style, because that file is only in the source zip. Every page shares one stylesheet, docs.css (from
build/docs.css), and there is no JavaScript, no web font and nothing fetched from another host.
check_docs_site.py parses every page and fails unless every internal link and #anchor resolves inside
OUT_DIR (the one link out is the header's, up to the Paracosm page), no page and no stylesheet fetches anything
from another host, every doc in the list has its page and a <doc title> - Paracosm docs title, and every table
sits in its own scrolling box. Publish by copying OUT_DIR as it is to docs/ beside the Paracosm page.
Never in a release
make_release.py refuses any of these in the source zip or the server zip.
| item | where | why |
|---|---|---|
.env |
source root | every password and token |
OpenSim.ini (and its .bak) |
bin/ |
the estate owner's and the console's passwords, in clear |
WorldBridge.token |
bin/ |
the gaia token: full control of the world |
*.db |
bin/ |
the world, every account and its password hash, inventories, groups |
Regions/Regions.ini |
bin/Regions/ |
this install's region UUID |
logs: OpenSim.log, OpenSimStats.log, opensim-console.out.log, WorldBridge.audit.log*, OpenSimConsoleHistory.txt |
bin/ |
names, chat and commands; a console history may hold typed passwords |
runtime state: opensim.pid, worldbridge-*.json, worldbridge-files/, assetcache/, ScriptEngines/, maptiles/, j2kDecodeCache/, addin-db-*/ |
bin/ |
this install's state and caches |
*.bak, *.bak-<stamp> |
bin/ |
leftovers of DLL swaps and make_config.py --force |
| a backup folder | backups/ or PARACOSM_BACKUP_DIR |
state/ holds OpenSim.ini and the token; the IARs hold inventories. Ship a world as region.oar alone |
assets/ |
source root | builder output, and any legacy _<name>_account.json login files (only the two versioned files named above ship) |
*.oar, *.iar |
anywhere in a zip | a world ships beside the zips, as worlds/*.oar; an IAR holds an inventory |
*.pfx, *.p12 |
anywhere | key containers |
tools/leap_bridge.log |
tools/ |
the viewer bridge's log |
| the viewer's own folders | %APPDATA%/ParacosmViewer_x64, %LOCALAPPDATA%/ParacosmViewer_x64 |
saved logins, chat logs, cache |
| the git history | .git/ |
retired demo values |