Repository navigation
Releases: scubamount/sco-core
Release list
sco-core SDK 2.3.0
See the SDK 2.3.0 release notes and the
SDK 2.3.0 scope record.
SDK 2.3.0 packages the entries below without changing frozen plugin ABI 1.1
(include/sco_api.h and tests/abi_v1.c are byte-identical to 2.2.0). Core, legacy,
core-source and host-source-sc use 2.3.0. The candidate adds the game service tables
game.asop 1.0 and game.contracts 1.0 and grows game.loadout to 1.1, so under the
game-pack policy (a release that adds or grows a game service raises the
minor) the game pack and the optional game-sc overlay move to 0.6.0
(SCO_GAME_PACK_VERSION, was 0.5.0; sco-sdk-game-sc-0.6.0.zip). Nothing below has run in the
game: evidence is macOS local builds and synthetic fixtures. Linux, native Windows, GPU and
real-game acceptance are unproven. The new game capabilities (game.asop.claim_timeout,
game.asop.shard_persisted, game.contracts.stream_radius, game.loadout.weapons,
game.pak.all_files) default OFF, and no production adapter turns them on.
game.loadout1.1: weapon and multitool slots 8-21 (vocabulary only),game.loadout.weaponsOFF (docs, contracts).include/sc_loadout.hadds fourteen slot names afterSC_LOADOUT_SLOT_VISOR:SC_LOADOUT_SLOT_PRIMARY(8) andSC_LOADOUT_SLOT_SIDEARM(9) for the weapons themselves;SC_LOADOUT_SLOT_PRIMARY_OPTIC,_PRIMARY_BARREL,_PRIMARY_UNDERBARREL(10-12) andSC_LOADOUT_SLOT_SIDEARM_OPTIC,_SIDEARM_BARREL,_SIDEARM_UNDERBARREL(13-15) for firearm attachments;SC_LOADOUT_SLOT_PRIMARY_TOOL_MODULE,_PRIMARY_TOOL_CANISTER,_PRIMARY_TOOL_BATTERY(16-18) andSC_LOADOUT_SLOT_SIDEARM_TOOL_MODULE,_SIDEARM_TOOL_CANISTER,_SIDEARM_TOOL_BATTERY(19-21) for multitool parts. The records are unchanged (sc_loadout_itemandsc_loadout_v1keep their layout and sizes); a slot number just encodes its parent weapon. Like the body slots these are logical slots, not engine port names, and a batch is still processed in input order, so a consumer sends slot 8 or 9 before the attachment slots it targets. There is no removal:item_classstays 1 to 95 bytes. The version follows thegame.world1.1 precedent:SC_LOADOUT_VERSION_1_0andSC_LOADOUT_VERSION_1_1are added,SC_LOADOUT_SERVICE_VERSIONstays 1.0 while 1.1 is published, so a 1.0 query is still answered. The new capabilitygame.loadout.weaponsdefaults OFF (evidence levelsynthetic_only): slots 8-21 reportSC_LOADOUT_UNSUPPORTEDwhen the installed backend does not declare weapon support and staySC_LOADOUT_UNAVAILABLEwhile the capability is off, with no engine call either way; a 1.0 host reportsSC_LOADOUT_UNSUPPORTEDfor them. There is still no production engine backend:src/game/services/spatial.cppis untouched, so the service starts without one and every slot, body or weapon, reportsSC_LOADOUT_UNAVAILABLEin game. Pinstests/abi_game_loadout.c; provider tests use a synthetic backend. Headless tests only: nothing has run in the game.sco.ui.surfaces1.0: renderer-neutral panel placement (sco_api.hunchanged), a host-owned service (docs, contracts). A plugin shows one of itssco.widgetspanels as a 2D HUD rectangle (SCO_SURFACE_HUD_2D), a camera-facing 3D billboard (SCO_SURFACE_BILLBOARD_3D) or a world-anchored 3D quad (SCO_SURFACE_QUAD_3D):register_surface,update_surface_pose,unregister_surface,last_errorover size-prefixedsco_surface_desc/sco_surface_pose(position, normal, up, size in metres, max distance, an occlusion-raycast flag, the panel id). The host validates every field (finite numbers, unit and perpendicular vectors, bounded sizes, distances and coordinates, 32 surfaces per plugin and 256 in all, panels under the plugin's own id), stores surfaces per plugin and withdraws them on unload or crash throughsco.ui's release hook (no new hook slot). Products read the registry throughsco/surfaces.h(Surfaces(),Revision(),CheckPose) and project it themselves;docs/ui.mddocuments the billboard and quad frames and the panel-to-pixel homography. C++ wrapperscosdk/ui_surfaces.hpp; C# and Lua are unsupported. Pinstests/abi_ui_surfaces.c, host teststests/test_surfaces.cpp; both ship in core-source, the headers in core. Headless tests only: nothing has run in the game.sco::game::pakScope::AllFiles(design plan PR 10), OFF by default: persistent swaps of
the four pinnedICryPakslots (open 0x148, read 0x160, seek 0x1D0, close 0x1E0) serve every
mounted path on every thread, through a sharded map of served handles.Enablerefuses it unless
the product sets the newOptions::allFilesProbed, which no sco-core caller does. The new
capabilitygame.pak.all_filesis registered OFF pending in-game confirmation. Tell, size and
eof slots have no row, so they are never swapped;QueryHandleandServedHandlesreport the
virtual position, size and eof of a served handle.Disabledrains: open served handles keep
their virtual file, and the slots go back when the last one closes. The mount check is guarded
likeOptions::onLoad(try/catch, and SEH on MSVC).Scope::DataCoreLoadbehaves as before.files/replacement mounts (sco/vfs.h):vfs::ReplaceMount(a whole-fileTransform,
refusing absolute, drive and./..game paths, inert at open when the file is missing or over
maxBytes) andvfs::FileMounts(a data pack'sfiles/folder, symlinks skipped). The plugin
content index doesn't listfiles/yet. Nothing here has run in the game: the evidence is
synthetic tests (test_pak_files) over a fakeICryPakvtable.
-
Game services: game.asop 1.0 (insurance claim timeout and IsShardPersisted reads), default OFF.
include/sc_asop.h: sc_asop_v1 (32 bytes, size-prefixed, version 1.0, pinned by
tests/abi_game_asop.c): claim_timeout, shard_persisted, last_error. Capabilities
game.asop.claim_timeout and game.asop.shard_persisted are held OFF (evidence level
off_pending_probe) until an in-game run confirms them; while off every call answers
SCO_UNAVAILABLE without touching the game. Both functions only read rows that already exist
in src/game/asop_sigs.cpp and that docs/game/asop.md documents (insurance.config at
kInsuranceTimeout, asop.shard_persisted); no row, hook, patch or write was added.
src/game/services/asop_service.cpp is the portable policy behind an AsopProvider seam;
src/game/services/asop_engine.cpp (Windows game pack) reads the rows under SEH. The vehicle
list, deliver, retrieve and claim rows stay unwrapped because the repository documents no
plugin-callable meaning for them (docs/game/asop-service.md). Tests: tests/test_asop.cpp
(synthetic provider) and abi_game_asop as C11, C++20 and -fshort-enums. Catalogue records
(sdk/contracts/sc_asop_v1.json) and docs/contracts.md rows added; C++, C# and Lua routes
unsupported. Registry entry, docs/game/status.md rows and sdk/native_index.json regenerated.
Nothing here has run in a game session. -
Game services: game.contracts 1.0 (mission stream radius read), default OFF.
include/sc_contracts.h: sc_contracts_v1 (24 bytes, size-prefixed, version 1.0, pinned by
tests/abi_game_contracts.c): stream_radius, last_error. Capability
game.contracts.stream_radius is held OFF (evidence level off_pending_probe) until an in-game
run confirms it; while off the call answers SCO_UNAVAILABLE without touching the game. The
function only reads the contracts.mission_settings row that already exists in
src/game/contracts_sigs.cpp and that docs/game/contracts.md documents (the float at
kStreamRadius); no row, hook, patch or write was added. The service name game.contracts was
unused; the host-internal contracts.* capabilities and game.missions are separate.
src/game/services/contracts_service.cpp is the portable policy behind a ContractsProvider seam;
src/game/services/contracts_engine.cpp (Windows game pack) reads the row under SEH. The other
contracts rows stay unwrapped (docs/game/contracts-service.md). Tests: tests/test_contracts.cpp
(synthetic provider) and abi_game_contracts as C11, C++20 and -fshort-enums. Catalogue records
(sdk/contracts/sc_contracts_v1.json) and docs/contracts.md rows added; C++, C# and Lua routes
unsupported. Registry entry, docs/game/status.md rows and sdk/native_index.json regenerated.
Nothing here has run in a game session.
sco-core SDK 2.2.0
See the SDK 2.2.0 release notes and the
SDK 2.2.0 scope decision.
SDK 2.2.0 packages the entries below without changing frozen plugin ABI 1.1
(include/sco_api.h and tests/abi_v1.c are byte-identical to 2.1.0). Core, legacy,
core-source and host-source-sc use 2.2.0. The maintainer kept the three new game service tables
in the candidate, so under the game-pack policy (a release that adds or grows
a game service raises the minor) the game pack and the optional game-sc overlay move to 0.5.0
(SCO_GAME_PACK_VERSION, was 0.4.0; sco-sdk-game-sc-0.5.0.zip). Nothing below
has run in the game: evidence is macOS local builds and synthetic fixtures. Linux, native
Windows, GPU and real-game acceptance are unproven. The new game capabilities
(game.hangar.lift, game.hangar.atc_cancel, game.reputation.checks,
game.world.free_camera_flag) default OFF, and no production adapter turns them on.
sco.widgets1.1 (additive): the table grows from 24 to 48 bytes with tail members
update_nodes(atomic subtree replace/insert),remove_nodes(refuses to empty a panel) and
capabilities(runtime limits by fixed index). Opt-insco_widget_node_1_1(severity,
tooltip, paged LIST/TABLE windows) andsco_widget_event_1_1(row; newSCO_WIDGET_EVENT_PAGE)
are selected by theirsizefield; panels without a 1.1 node keep byte-identical 1.0 events.
The ImGui adapter draws severity, tooltips and Previous/Next paging, and rebuilds a shared
render snapshot only when a panel changes. 1.0 pins are unchanged except the table size.
sco-plugin-checkremains a 1.0 stand-in; the C++, C# and Lua wrappers expose 1.0 only.
Headless ImGui-shim fixtures only; GPU rendering not verified.- C++
scosdk::PanelBuilder(include/scosdk/menu_builder.hpp): header-only C++20
declarative Row/Column panels forsco.widgets1.0 with typed bindings, preorder ids,
host-equivalentValidateWidgetNodesand callback dispatch that tolerates a callback
destroying its own tree. Compared with the real host on 27 node arrays; ASan clean. - C#
Sco.Sdk.PanelBuilder: fluent Column/Row/Button/Toggle/Slider builder over
sco.widgets1.0 with explicit stable ids, frozen build snapshots and typed dispatch.
Not compiled locally (no .NET SDK on the preparing host); the hosted
sdk/csharp-host-simjob is its first build. - Lua
sco.panel_builder: embedded module installed in every plugin sandbox (new(),
column/row,toggle/slider/button,build()returning node snapshots plus a
dispatcher). Runs inside the existing instruction and memory budgets; norequire,
filesystem or bytecode. - POSIX diagnostics transport recovery: an owner that died without cleanup no longer
blocks every later session. The mapping is published atomically and held underflock; a
stale entry is reclaimed only by the holder of its lock after identity re-checks, peers refuse
a dead owner's mapping, and peer leases are removed on release. Fails closed on the remaining
crash windows. macOS only; Linux unverified. - Game status registry (repository only):
sdk/status_registry.jsongenerates the service
table indocs/game/status.md;tools/status_registry.py --checkruns intest.yml. No
evidence level was raised. - Documentation gate: the public documentation set must name the function, table or test
instead of citing source by line number. A scheduled, read-onlylive-sitejob in
docs-site.ymlchecks that the deployed docs site is fresh againstmain. - Game tables (game-sc headers, host-source-sc implementation):
game.hangar1.0
(include/sc_hangar.h: lift open/close request for a landing area, ATC request cancel),
game.reputation1.0 (include/sc_reputation.h: read-only state of the reputation check
sites) andgame.world1.1 (include/sc_world.hgrows 32 to 40 bytes with the read-only
free_camera_flagtail member). ABI pins intests/abi_game_hangar.c,
tests/abi_game_reputation.candtests/abi_game_world.c; host-sim contract tests
hangar,reputationandworld_free_cam. Windows game-pack adapters are not built or run
locally; no wrapper language exposes these tables yet. - Plugin scaffolder (
sdk/tools/sco-new-plugin.py, shipped astools/sco-new-plugin.pyin
core and core-source): writes a buildable C or C++20 native plugin with optional
--with-menupanel and optional service lookups (logged when missing, never required), and
its CMakechecktarget runssco-plugin-check. It refuses to overwrite files or write
through symbolic links.sdk/test_new_plugin.pybuilds the generated projects on macOS; it
is not wired into CI yet and MSVC builds are unverified. - Engine-native index (repository, site and MCP only, in no SDK zip):
sdk/native_index.json
lists every signature row by id, subsystem, symbolic hash and promotion tier, generated by
tools/native_index.pyand checked intest.yml. The docs site renders it at/natives/
inside four new library hubs, with a downloadable copy of the same JSON. Rows name readiness
only: no patterns, masks, offsets or addresses. Publication follows the
2026-10-14 native-index decision. - Discovery MCP server, opt-in tools (repository only):
tools/sco-core-mcpoffers four
tools behind--extended-tools; the default six tools and the documented launcher are
unchanged.list_engine_nativesandget_engine_nativereadsdk/native_index.jsonand
refuse a malformed index whole.validate_manifest_and_widgetsports thesco-plugin-check
manifest rules and checkssco.widgetsnode arrays.generate_plugin_scaffoldreturns the
filessco-new-plugin.pywould write as text and writes nothing; it runs the granted
checkout's scaffolder in the server's own process, so grant only a reviewed checkout.
Service evidence now preferssdk/status_registry.jsonand never reports gameplay
verification. - Docs site: pages are grouped into four library hubs (start and SDK profiles, language
SDKs and cookbooks, native and service reference, host integration and AI agents) with no
route moved. Page titles no longer show code backticks. - Getting started:
docs/getting-started.mddownloads, verifies and builds against the
2.2.0 core archive; the game extension issco-sdk-game-sc-0.5.0.zip.
sco-core SDK 2.1.0
SDK 2.1.0 packages the engineering entries below without changing frozen plugin ABI 1.1.
The additive game contracts raise the separate game-sc package coordinate from 0.3.0 to
0.4.0; core, legacy, core-source and host-source-sc use 2.1.0. The optional game-sc overlay
binds the exact core archive digest. All five profiles are selected for candidate generation;
publication still requires approval of the final bytes and a maintainer signature. Product
export remains excluded.
The SDK2.1 scope decision
records maintainer scope review, not final signed-byte publication approval.
Native Windows CI fixtures are no-game engineering evidence, not engine or gameplay
acceptance. Preserve each entry's historical verification limits: real-game, anti-cheat,
official-network, private-LAN/firewall and renderer acceptance are not established by this
release preparation. Default-off and fail-closed capability controls remain unchanged.
-
Renderer-neutral text inputs gain
SCO_WIDGET_PASSWORDdisplay masking for explicit G13 credentials; only text inputs accept the flag. This is not encrypted storage or a guarantee against host-memory disclosure. -
G13 private-session broker (R1): owner-approved default-on
SessionControlV1
with strict loopback/no-startup-socket defaults, explicit numeric private bind
and exact peer allowlist, 12-byte minimum passphrase, bounded ingress/requests,
fail-closed offline/EAC admission and credential-free lifecycle audit. Add
publicgame.private_session1.0 Host/Join/Leave/state requests for the external
multiplayer plugin; sockets and policy remain host-only. Host kit publishes
before plugin load, checks admission before queued work, and stops on admission
loss/unload/quit using the existing net release dispatcher. Synthetic backend
and C layout proof only; Windows/MSVC/private-LAN/game NOT VERIFIED. G2 unchanged. -
Runtime MCP step 2 — host IPC/auth gate (local fixture): default-off host-private mapping, secure per-session credentials/peer lease, mutual directional HMAC and six copied-metadata reads; hostile real-transport and literal-vector fixtures. No sockets, network-key reuse, public ABI change or product/MCP enablement. Protected OS audit/product policy remains step 3; not run in game.
-
C#
sco.widgets1.0 (#142): pinned interop, bounded copied trees, typed rooted callbacks, atomic failures/reentrant updates and archive example/tests; frozen ABI unchanged. Windows NativeAOT/GPU/game not verified locally. -
Lua
sco.widgets1.0 (#143): sandboxed bounded declarative panels for all eight
widget kinds and ROW/COLUMN, typed copied events, registry-rooted callbacks until
successful replacement/removal or unload, atomic failures and reentrant updates.
Complete member-extent/null guards, shared instruction/memory budgets and real
neutral-host lifecycle fixtures; archive-containedwidgets_luaexample.
Frozen ABI unchanged; GPU rendering/gameplay not verified. -
G17 diagnostics publishers (#141): add default-off Star Citizen minimal
metadata snapshots and a host-owned, selected-ownersco.diagnostics.publisher
1.0 ingress for fixed advisory plugin health. Sources require explicit opt-in
and positive host offline admission; copy into the existing immutable host
diagnostics path without plugin callbacks, scanner execution or side channels.
Extra source fields stay internal: runtime JSON v1 is unchanged and arbitrary
plugin fields/gameplay data are not accepted. Optional SDK example ships
disabled; synthetic module, ABI and truncated-tail fixtures added. Frozen
sco_apiunchanged. Windows/MSVC, endpoint security and gameplay not verified. -
G14 content access (#135): audit confirms the private content index and
command registry lacked a public list/script read route. Add kernel-neutral
sco.content1.0 with bounded copied startup records/bytes, link-safe reads,
whole-pack refusal, dependency propagation, and guarded C++ access. Packs are
prepared before consumer code loads; code-provider dependencies are explicitly
refused. Public C example, synthetic module/layout tests, catalogue, packaging
and provenance added. Frozensco_apiunchanged; no allowlist expansion.
Not run in game; C#/Lua and product step-2C migration remain downstream. -
Offline host DataCore timing (G1): initialize/index before early engine
loading, bounded CryPak transform, preserve LOADED across app Start and drain
producers before teardown. Synthetic early-load/late-refusal fixture passes;
Windows transport and legacy builtin migration remain unverified. -
Offline host quit adapter (G1): required validated CSystem quit hook by
default, synchronous stop before both engine quit paths, original argument
passthrough, repeated-stop/task-cancellation fixtures and explicit external
quit integration. No product fast-shutdown field reads; actual Windows detour
and game shutdown not verified. -
Offline host tick adapter (G1): game-thread cadence/wrap handling, first-pass
tick, fresh admission checks even on throttled passes, shutdown/cancellation on
lost offline evidence, and no feature fallback after a plugin fault. OS message
and renderer integration remain in the shell; synthetic fixtures only. -
Offline host composition, admission/resolve/start (G1): add game-only
sco_game_hostC++ host-source target. Unknown/online/EAC/unblocked-network/wrong
target evidence refuses before any signature resolution or publication; startup
revalidates admission, owns row resolution and starts the existing app kit.
Synthetic lifecycle/thread fixtures only; no online-to-offline conversion,
plugin patch service or frozen ABI change. Legacy offline mutations and product
migration remain separate; not run in game. -
G16 Star Citizen host-source candidate kit:
host-source-scpackages the neutral kernel plus complete tracked game implementation, DataCore, private headers, vendored dependencies and synthetic test inputs in a standalone source layout. Existing SPDX SBOM, provenance and checksum generation is retained; an extracted-archive regression builds the G1 host adapter targets withSCO_GAME_SC=ON, runs five synthetic host fixtures and checkscore-sourcegame exclusions. All six private adapter files are included. Linux and MSVC SDK CI now run this extracted-kit check, and the release candidate includes this fifth profile. Frozen plugin ABI and human signing/publication gates remain unchanged; gameplay validation is still owed. -
Legacy wrapper admission: reject incomplete or null callable members in matching C++, C# and Lua routes, and require cleanup callbacks before creating owned cursors, channels, patches or UI registrations. Public fake-provider regressions run against extracted SDK headers; managed game fixtures cover partial and null callbacks. No game execution or frozen ABI change.
-
G2 relocation foundation: size-prefixed
game.relocationrequest/cancel/status and tested owner-scoped streaming completion state machinery. Production mutation remains unavailable until host safety/session admission, system classification and validated transport are grounded; not Windows/game verified. -
G3
game.spatial1.0: new size-prefixed native C/raw C++ full-pose conversion
plus bounded copied zone records, exact observed-name lookup and epoch-pinned
pages. At most 256 observed IDs/64 records per page; complete rigid ancestry only,
no global scanner or raw pointers.teleport.spatial1.0 andsco_api1.1 stay
unchanged. Root ancestry is exposed, but system classification remains explicitly
unknown rather than guessed. C#/Lua unsupported; portable synthetic/ABI fixtures,
not verified on Windows or in game. -
G4 (#125) owned prefab spawning: independent
game.prefabs1.0 validates
canonical content-relative paths and bounded owned quotas, ports the existing
object-container attribute writer, and records pending prefab ownership in the
existing entities ledger for move/despawn/retained undo and ordinary unload.
Owner-approved R1 default removes the hard-disable forgame.entities.prefabs;
canonical 511-byte paths, finite normalized poses, shared 1,024/per-owner 128
quotas and existing readiness/cleanup/fault refusals are unchanged. C/C++
routes and synthetic/ABI/catalogue/package evidence only: Windows/MSVC,
native SEH and streamed spawn/removal behavior are NOT VERIFIED; not run
in game. Frozen ABI unchanged; no arbitrary delete, content exports or private
product fallback. G5/G9 behavior is unchanged. -
G5 (#126):
game.world.control1.0 adds owner-validated bounded filtered
rays and exclusive reversible free-camera leases, with native C/C++ routes,
synthetic restoration/ownership/fault fixtures and ABI/catalogue/package pins.
game.world1.0 and frozensco_apiremain unchanged. New production
capabilities are OFF: no verified offline engine adapter, no guessed offsets.
Ordinary unload/stop restoration is policy-tested; Windows/game not verified. -
G9 retained-build and owned-seat removal: new game-only
game.owned1.0
table keeps explicitly retainedgame.entitiesplacements owned for undo/clear
while loaded and removes them on ordinary unload; no across-reload persistence.
Actors-owned NPC and expected-seat-occupant removal are separate authorities;
foreign/player occupants and arbitrary deletion remain forbidden. Bounded
owner-scoped receipts report removal initiation only, neveralive=0completion.
C/C++ direct route, C#/Lua explicitly unsupported; synthetic fixtures only,
not run in game. Frozen base and existing service layouts remain unchanged. -
G6 typed offline player loadout (
game.loadout1.0): bounded 16-slot C/C++
synchronous apply, copied input validation and explicit partial/unsupported/missing
slot r...
sco-core SDK 2.0.0
The plugin ABI remains 1.1, unchanged. The SDK major version reflects breaking packaging/profile and release-process changes: separate core and game extension archives, an independently buildable core-source kit, and build-once promotion requiring a signed, hash-bound maintainer approval.
The prepared sdk-v1.2.0 was never published; its entries are folded into this release below.
-
Windows extracted-SDK verification: the archive-test job checks out the packaging verifier and its complete manifest inputs, rather than only the shell runner. The verifier reads evaluated MSBuild toolchain include paths so Windows SDK/CRT headers are recognized without relying on the shell's
INCLUDE. Builds remain confined to extracted SDK headers, with compiler-resolved checkout leakage refused. -
Extracted SDK storage and public-header proof: storage resolves host-owned directory aliases before SQLite opens the database, fixing macOS temporary-root failures without permitting database-file symlinks. External C/C++ examples now compile with exact compiler-resolved installed public-header membership checks; hidden checkout and unshipped nested dependencies are refused. Packaging also refuses recognized private-key and GitHub credential shapes before writing an archive. No plugin ABI change.
-
Optional ImGui coupling is host-specific, not the frozen C ABI: document the exact source/configuration match and public-header hashes, drawing-plugin rebuild requirements and absence of cross-version raw-context compatibility; non-drawing plugins do not require ImGui.
-
Native trust and Lua reload limits: native plugins are trusted in-process code, not a sandbox or a native-fault recovery guarantee; supported cached-table, worker and shutdown usage is explicit. Real-loader Lua tests cover repeated reload resource/callback cleanup, transaction rollback, persistent data, preserved budgets and optional read-only game-adapter boundaries. No runtime or ABI change.
-
Real-host SDK conformance: independent native C consumers execute inspector, owned-NPC and actor-death contract fixtures through the neutral loader and host API; negative cases cover service absence/version/partial tails, ownership, wrong-thread raw calls, queued-work cancellation, and restart-required native provider refusal/fault retention. Engine responses are synthetic, not gameplay or native-process recovery certification.
-
SDK discovery acceptance: conventional Copilot/IDE integration docs include an explicit read-only tool allowlist; static language views and real-browser search/keyboard checks cover the reference site, with deterministic cold-Pagefind readiness before shortcut focus checks, and local snapshot tooling binds catalogue/examples to exact source and archive inputs without approval, signing or deployment.
-
Language-route evidence: catalogue mappings require language-specific tests; C/C++ and Lua actor/entity fixtures reject partial/null methods, C# wrappers clear failed-reopen state, and docs distinguish Windows x64 NativeAOT/host evidence from synthetic game-contract tests and unsupported routes. The C ABI is unchanged.
-
Strict neutral source SDK and macOS ARM64 development builds: the
core-sourcearchive excludes game ABI headers, layout pins, examples and game-only test fragments, while retaining generic scanner/hook/host coverage. Packaging tests build and run every neutral CTest from an empty extraction and resolve external example includes to exact shipped public headers. VFS snapshots work on C++20 libraries without atomic shared-pointer specialization; ARM64 detours remain explicitly unsupported. The plugin ABI is unchanged. -
Local SDK discovery:
tools/sco-core-mcp/adds a stdlib, read-only MCP stdio server with six catalogue tools, bounded example reads and source provenance; development aid only, with no SDK execution or game access. -
Static SDK documentation: a catalogue-backed site with local search builds as a read-only CI artifact for pull requests; trusted
mainpushes and manual dispatches deploy the validated site to GitHub Pages; project-authored site sources and dependency licence metadata are recorded, and the site is excluded from every SDK package profile. -
Release promotion refusal coverage: candidate, mandatory-check and draft round-trip logic now lives in testable stdlib tooling; signed negative tests cover the release refusal matrix and reject checkout-local signer policies.
-
Machine-readable SDK contracts:
sdk/contracts/records all 117 table methods and three native entrypoints, with compiler-validated signatures/extents, language evidence and explicit unspecified semantics;tools/sdk_catalogue.pybuilds a deterministic versioned JSON catalogue, and CI rejects inventory, documentation and support-claim drift. -
Signed release manifests:
tools/release_verify.pybinds publication approval to exact payload hashes, source and recursive dependency commits, builder identity and a maintainer SSH signature; negative tests cover tampering and fail-closed refusals. -
Faulted native providers are restart-required, not recovered. Attributed faults withdraw lookup and host scheduling; handed-out providers retain their state and mapped code without unload or resource release hooks. Logs, plugin reports and reload refusal tell the player to restart the game. Off-thread faults outside a host guard remain uncontained; cached tables and native process integrity are not guaranteed. No plugin ABI change.
-
Service-table unload admission is atomic across lifecycle paths: a single loader gate blocks new queries before teardown, protects built-in provider state, retains backing state after a queried failed load, and reserves the entire dependent reload cascade before any member changes. Command, UI and host API reload routes share this gate; the plugin ABI is unchanged.
-
SDK releases build once and promote verified bytes: a manual candidate workflow packages all four SDK profiles with SBOMs and provenance; tag publication requires a signed, hash-bound approval, downloads exact artifact IDs, and re-verifies a complete draft before making it public.
-
Direct native unload now respects service-table lifetime, matching
UnloadOne, app reload andsco.reload:UnloadNativerefuses a native whose table was handed out before its unload export or owner release runs. Shutdown still tears it down while keeping its module mapped. The lifetime audit inventories built-in tables, accessors and lifecycle paths, and separates administrative refusal from fault/withdrawal/shutdown behavior.TestServicesproves refusal through both public unload routes and retained shutdown pinning;sco_api.hand all table layouts are unchanged. -
Service contracts and a kernel source SDK. The contract catalogue inventories the 117 public table methods and three plugin entrypoints, with buffer/tail rules, ownership, thread/reentrancy, failures, capability absence and cleanup; unestablished guarantees are explicitly unspecified.
sdk/package.py --profile core-sourceproduces an independently buildable kernel source kit, without game implementation, andsdk/test-zip.shbuilds it from an empty extraction withSCO_GAME_SC=OFF. The kernel-only CI dependency gate now consumes the generated CMake target graph, compile commands, compiler depfiles and object/link inputs, with negative tests; symbol scans remain supplementary. The frozen 1.1 header is included and hash-checked for offline source builds. No ABI or gameplay behavior change. -
Discovery refuses a plugin folder whose id belongs to a built-in, and says why (
sco_api.hunchanged; plugins). A folder — native, Lua or data pack — whoseidis one of the host's built-ins (opts.builtins, filled bysco::app::StartfromPlatform::builtins) is refused at discovery, before the api and entry checks and before any plugin code runs, withrefused: id 'teleport' belongs to a built-in plugin: the log line and the plugin'sreason(sostatusandsco-plugin-checkshow it) both name the id, instead of the old unclearrefused teleport: host passed no api or ownerthat a data pack never got at all. The conflict is checked beforeentry 'x' not found, so a folder that may not load never has its entry opened. A disabled folder is not loaded, so it staysdisabledand appends the same reason todisabled file. Ids are[a-z0-9_]on both sides, so the match is exact and case needs no folding.requiresresolution is unchanged: a built-in still provides by its id. Tests:tests/test_plugins.cppTestDiscover(native, Lua, data, disabled, missing-entry, a non-conflicting id still ready, the status line and the log) andtests/test_app.cppTestBuiltinIdConflict(the same throughsco::app::Start, with the built-in itself still loaded and working). -
The plugin ABI 1.1 is frozen, with a golden and an old-binary test (
sco_api.hunchanged; no behavior change).tools/abi_snapshot.pycompiles a probe againstinclude/sco_api.hand compares itssizeof/_Alignof/offsetof/ enum / macro output — the 128-bytesco_apitable with every field offset and the function pointer order, every public struct, every result code, both version macros, the reserved padding — with the newtests/abi/sco_api-v1.1.golden, and checks that the header as released at tagsdk-v1.1.0still hashes to the sha256 the golden records. The pin is the semantic surface, not the bytes:sco_api.h's comments have changed since that release (its licence note), its declarations have not. The tool has no auto-update mode: a difference prints the diff and fails, and a deliberate 1.x addition hand-edits the golden in the same PR — which is what catches a PR that editstests/abi_v1.cand the header together. The second half is `tests/fixtures/plugi...
sco-core SDK 1.1.0
The first SDK release. The plugin ABI is version 1.1 and stable from here on: version 1 only grows at the end of structs, so plugins built with this SDK keep loading in later 1.x hosts.
- One ABI, five ways to write a plugin: C against
sco_api.h, C++20 withscosdk/, C# withSco.Sdk(published with NativeAOT, no .NET needed by players), sandboxed Lua 5.4, and data packs with no code. - Host services, each with its own pinned header:
sco.storage(per-plugin key-value and SQL over SQLite, crash-safe),sco.ui(menu tabs, overlays, badges, hotkeys bound to commands),sco.datacore1.1 (DataCore overrides, new instances and new records, applied at the game's data load or saved for the next launch). Plugins provide services and raw handlers to each other. - Data mods that survive game patches:
.tomlpacks address DataCore records and fields by name;sco-dcblints them and checks them against a game build. - Host side for products: the host kit, built-in plugins, crash containment, the detour engine, 64-bit engine math and the zone tree, virtual game files (
sco::vfs,sco::game::pak), and the signature tables withsco-sigcheck. - SDK zip
sco-sdk-1.1.0.zip: headers, template, seven examples (hello,cpp_hello,cs_hello,greeter,notebook,travel_pack,quantum_pack), the CMake helper andsco-plugin-check, each example built and checked from the zip on Linux and Windows in CI.
Every change since the first commit, newest first:
teleport.to_camerasurvives Star Citizen 4.10.196 (the 2026-10-09 patch,StarCitizen.exe4.10.196.36804): the row failed with "layout changed at +0x17a" because the four camera fields the handler loads at +0x17A..+0x1BD moved by 8 bytes (0x6D3C->0x6D44, ...); the code around them was unchanged. Those checks now pin the instructions (vmovss/vmovups/vmovsdfrom[rax+disp32]) and wildcard the field offset, which nothing reads.sco-sigcheck: 8/8 OK on both 4.10.193.11644 and 4.10.196.36804 (the three dependentteleport.*rows resolve again).- C# SDK layer (
sdk/csharp/Sco.Sdk, docs;sco_api.hunchanged): a .NET 8 library with no package references oversco_api.h1.1,sco_storage.h,sco_ui.handsco_datacore.h: blittable[StructLayout(Sequential)]structs withdelegate* unmanaged[Cdecl]function pointers, and wrappers mirroringscosdk/:PluginwithOnLoad/OnUnload, logging,CommandBuilder/Args/Reply,Subscribehandles (one host subscription per event, handlers multiplexed),RunOnGameThread,Invoke/InvokeAsync,Provide/Query/ServiceRef<T>.Coverswith the size check,RegisterRaw/InvokeRawwith the size handshake,Storage,DataCore/DataCorePatchandUi. Callbacks are[UnmanagedCallersOnly]trampolines whose ctx is an id into a registry swept at unload (never aGCHandle); command strings live in a native arena until unload; no exception crosses into native code (logged;SCO_FAILEDand<name> failed: <message>for commands). Plugins are published with NativeAOT (PublishAot,NativeLib=Shared) into one self-contained DLL with the three exports. New examplesdk/examples/cs_hello(cs_hello.wave <name>,cs_hello.ticks, thecs_hello.greeterservice,game.readyandtick). TestSco.Sdk.Tests: everySIZE/AT/PINline oftests/abi_*.cchecked against the C# structs (and, given the C files, the copy must equal them line for line), plus the wrappers against a stand-in host table (exceptions, multiplexing, tasks, the raw handshake, a late call after unload). The SDK zip shipscsharp/,cs_helloanddocs/sdk-csharp.md;sdk/test-zip.shwithSCO_SDK_CSHARP=1runs the test and publishes and checkscs_hello(the sdk workflow: linux-x64 and win-x64), and the new jobcsharp-host-simloadscs_hellothroughsco-host-simon Windows. sc-offline needs no change. - New records in data packs and
sco.datacore1.1 (design decision 3, "AddRecord in v1";sco_api.hunchanged). The pack format gains[[record]](struct,name,clone= a record of the same struct; optionalidshared with[[instance]]ids,guid,file,set), run throughPatch::AddRecordwith R1's rules; later operations name the new record by name, GUID or"@id"(its root). Withoutguidthe GUID is derived from the plugin id and the record name (PackRecordGuid), so it is the same at every launch; withoutfilethe path islibs/foundry/records/sco/<plugin id>/<name>.xml.lintchecks the required keys, a clone that is a record (nofield), the file path rule, and a name or GUID added twice by one file; the rest is refused at the load like the patcher's other rules. The service'sadd_recordnow queues a[[record]](before the load it applies at it; after it, it is saved inpending/<plugin id>.tomland applies from the next launch) and returns an id usable like an added instance's. The table and its layout are unchanged; the version becomes 1.1 (SCO_DATACORE_VERSION_1_1) so a caller that needs records can query for it and a 1.0 host (which answersadd_recordwithSCO_UNAVAILABLE) is told at the query.scosdk/datacore.hpp:AddRecord(type, name, cloneRecord, guid, filePath)returns aDataCoreInstance(was asco_result), plusDataCore::AddRecordSupported(). sco-lua:p:add_record(type, name, clone_record [, guid [, file]])returns the record's root as an instance.sco-dcb diffturns a record only in b into a[[record]]cloned from the closest record of a of the same struct, then sets what differs (new records first). Tests: golden fixtures (good_record.tomland the refusals: no struct, no clone, clone with a field, name or GUID added twice, zero GUID, file path prefix and extension, an id shared with an instance),test_datacore_pack(applied values, default GUID and path, every load-time refusal, two packs adding one name, atomic = false),test_datacore_service(add_record before the load through scosdk; after it saved and applied at the next simulated launch with its derived GUID),test_lua,tests/dcb_pack.cmake(lint, check, show and a diff round trip oftests/fixtures/datacore/new_record),abi_datacore(the 1.1 constant). For sc-offline: nothing to change; plugins that add records need a host with sco.datacore 1.1. - sco-lua:
sco.store, storage for Lua plugins over the host servicesco.storage1.0 (sco_api.handsco_storage.hunchanged; Lua reference).get(a string, ornilwhen there is no such key),put,delete(true/false),keys(prefix, after, limit)(a list, at most 1000 per call, paged withafter),begin/commit/rollback,exec(sql, params)(rows changed) andsql(sql, params)(rows as{ column = value }tables, at most 1000, more istoo_many) orsql(sql, params, fn)(fn(row)per row until it returnsfalse). Parameters: integers, numbers, strings, booleans,nilwithn. Errors arenil, err, message(the service'slast_error); a host without the service (an older one, or no data folder) keepssco.storeand answersnil, "unavailable";sco.store.available()tells. Each call and each row or key read counts 100 steps against the step budget;sqlholds its cursor in a to-be-closed slot, so it is closed on return and when an error unwinds through it (a script error infn, the budget running out, no memory). Nothing names a file.lua-check.luagains an in-memorysco.store(no SQL); the SDK gains the exampleexamples/notebook(notes in a transaction), checked bylua-checkand installed insdk/test-zip.sh. Tests:test_lua(round trip, two scripts isolated, SQL with parameters and types, the row cap, an error mid-iteration 70 times with no cursor left open, the budget running out inside a row function, a reload keeping committed data, no service and a sco_api 1.0 host, the notebook example). For sc-offline: Lua plugins get storage oncepf.dataRootis set. - The
sco.datacoreservice 1.0 (include/sco_datacore.h, plain C, ids never pointers, pinned bytests/abi_datacore.c; host sidesco/datacore_service.h, librarysco_datacore_service;sco_api.hunchanged), plan PR 6 of the DataCore design (docs). A host-owned service, published only when the product setssco::app::Platform::dataCore(off by default; sc-offline turns it on in design plan PR 8).state(SCO_DC_OPEN/SCO_DC_LOADED),begin,set,add_instance,set_pointer,append,add_record(answersSCO_UNAVAILABLE: saved patches use the pack format, which has no record operation yet), values includingSCO_DC_REFfor reference fields,commit,discard,report. Before the DataCore load a committed patch is queued for it; after it (decision 9)commitsaves the patch as<dataRoot>/datacore/pending/<plugin id>.toml(temporary file plus rename) and reportsSCO_DC_QUEUED"applies at the next launch"; the next load applies it right after the plugin's own data pack, and skips (and logs) the saved patch of a plugin no longer installed or enabled.service::Loadapplies data packs, saved patches and queued patches in plugin order with per-patch atomicity (SCO_DC_NON_ATOMIC), fills each patch's report and posts the eventdatacore.applied(sco_dc_applied). sco-lua gainssco.datacore(begin,state; patch methodsset,add_instance,set_pointer,append,add_record,commit,discard,report) when the host publishes it;scosdk/datacore.hpp(DataCore,DataCorePatch,DataCoreInstance); the SDK zip shipssco_datacore.h. Pack reasons for operations without a line (patches built in code) name the operation number. Tests:tests/test_datacore_service.cpp(a simulated launch sequence: load, commit after it, the next launch applying t...