← Paracosm·Docs/Handbook
Contents · Packaging a release

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.

  1. 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
    
  2. Configure: C:\paracosm\viewer-build\configure.bat (autobuild with --opensim --chan Paracosm and LL_TESTS=FALSE). It ends with CONFIGURE_EXIT=0.

  3. Build: C:\paracosm\viewer-build\build.bat (msbuild directly, at low priority). It ends with BUILD_EXIT=0. A first build takes about half an hour.

  4. Package:

    python C:/paracosm/viewer-build/package.py [--out C:/fs/paracosm-package]
    

    It runs Firestorm's own viewer_manifest.py with the copy package actions into <out>/Firestorm-Paracosm/, which lays out a runnable viewer (the exe with its app_settings, character, fonts, skins and 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), writes README-FIRST.txt, and zips the folder as <out>/Firestorm-Paracosm-<version>-win64-portable.zip (the version from the build's viewer_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