SECS — Scripting Engine C Sharp
A game-agnostic scripting and modding engine inspired by Paradox games (CK3, EU4, Victoria 3). SECS uses modified C# as its scripting language — .secs files are real C# with extensions for game scripting. The SECS compiler transpiles them to standard C# that integrates with the engine runtime.
Status: The v2 runtime is built and tested (SECS.Core, SECS.Native, SECS.Schema, SECS.Kernel, SECS.Runtime, SECS.Adapters.Standalone, SECS.Compiler.Contracts — per AD-0006). The 6-phase HardOverride channel pipeline and activity/policy mod finalization are implemented. The Roslyn fork is present as secs-roslyn/; Phase 1 ships the current backed .secs compiler slice and emits schema-owned generated output for the active examples. Broader language lowering remains future work. See TASKS.md for current status.
The v2 kernel / runtime / schema / native / standalone assemblies are the active architecture; examples/valenar-v2/Server is an ASP.NET Core SignalR hub at /gamehub wrapping the v2 runtime, and examples/valenar-v2/Client is the React/SignalR Valenar frontend pointed at that hub through @microsoft/signalr + zustand. Implemented v2 domains include shell, character sheet, skills, inventory starter/equip/use/move/static item definitions, retained policy catalog/rule dispatch, activity catalog/runs/queue, pending choices, tooltip, time-bank and game speed, graph travel, map geometry/biomes/hierarchy, Territory knowledge, source-authored forced Feature follow-through, Stage-0 objectives, session milestone journal, MakeCamp-created camp state plus Rest, direct combat preview/resolve plus auto-resolved travel encounters, bootstrapped settlement/building, and retained economy systems through market scaffold. Retired deletion-target surfaces are recorded in the v1 deletion gate.
Active v2 work lives at top-level
src/,tests/,examples/, andunity/. Unity-hosted game packages underunity/are adapters/examples around the deterministic SECS engine; engine authority remains insrc/SECS.*. New work targets v2 — seedocs/adr/ad-0006-secs-v2-kernel-rewrite.md.
Architecture
src/
SECS.Core/ Typed IDs, FNV-1a hash, shared types — netstandard2.1
SECS.Native/ SECS-owned native collections (managed-backed initially) — netstandard2.1
SECS.Schema/ WorldSchema and schema row types — netstandard2.1
SECS.Kernel/ Deterministic semantic kernel (entity table, relations, modifier indexes,
channel snapshots, command journal, save sections) — netstandard2.1
SECS.Runtime/ Runtime coordinator (tick pipeline, channel resolver, event/activity/policy
dispatch, mod registry) — netstandard2.1
SECS.Adapters.Standalone/ Reference adapter for standalone C#/ASP.NET Core — net8.0
SECS.Compiler.Contracts/ Compiler-emit types (WorldSchema, QueryPlan, ContentManifest,
ExecutionLane, CommandJournal) — netstandard2.1
examples/
minimal-v2/ Minimal v2 standalone example
character-trainer-v2/ v2 character-trainer host
valenar-v2/ v2 Valenar host (active compiler oracle and runtime target)
endgate/ Focused v2 prototype (SignalR server, React/Vite client, benchmarks)
map/ Map-generation prototypes (mapv10 is the active continent-scale direction)
unity/
combat-slice/ Self-contained Unity-hosted combat prototype package
ark-extraction/ Self-contained Unity-hosted ark extraction prototype package
packages/ Shared game-neutral Unity packages
The engine is game-agnostic. Channels, modifiers, contracts, scopes, and templates are all defined by the game — SECS provides the mechanisms.
Documentation
Start with the Design Reading Guide. That is the entry point for the live SECS docs and sends first-pass readers on to 00 — Overview. Historical, audit, and backlog material remains available under docs/, but the live design path is the authoritative reading route.
For a local docs portal, install the Docusaurus dependencies once:
npm install --prefix docs-site
Live authoring stays on a fixed loopback-only dev server:
npm run dev --prefix docs-site
That serves the portal at http://127.0.0.1:4174/secs/.
The stable personal-portal mode is build-first preview on loopback:
bash scripts/run-docs-portal.sh
That rebuilds the site, serves the built docs at http://127.0.0.1:4173/secs/, and starts a small loopback landing page plus zellij proxy at http://127.0.0.1:4180/. The landing page links to the docs portal and proxies non-root requests to the existing zellij web client on http://127.0.0.1:8082, with /zellij as the stable entry path. The underlying manual commands are npm run build --prefix docs-site, npm run serve --prefix docs-site, and npm run check --prefix docs-site.
The Docusaurus portal is built from generated publish content under docs-site/content/. Edit root SECS docs in docs/, Valenar docs in docs-site/content/valenar/, map docs in examples/map/mapv10/, and governance docs in .claude/rules/ or .github/, then rerun npm run check --prefix docs-site.
The portal syncs every Markdown file under docs/ and preserves the Valenar publish tree under docs-site/content/valenar/. For mapv10, it syncs the top-level mapv10 Markdown files plus the documentation-bearing subtrees (docs/, generator/, viewer/, schema/, viewer/src/{data,events,renderer,ui}/, prompts/, and verification/visual-foundation-audit/) without crawling generated map artifacts or dependency folders. npm run dev --prefix docs-site starts a watcher that resyncs source-doc changes while Docusaurus is running, so edits and newly added pages reload without restarting the dev server. npm run build --prefix docs-site and npm run check --prefix docs-site perform a fresh sync before building. For one-off manual syncs, run npm run sync --prefix docs-site.
Sidebars are generated from the synced doc tree by docs-site/sidebars/auto.js. Keep only high-level grouping rules there; do not hand-maintain leaf pages in the sidebars. New docs automatically appear in the left menu under their source-tree group, with unknown paths falling into an Other section until the grouping rules are intentionally refined.
On Linux, install the systemd user service for login-time autostart with:
bash scripts/install-docs-portal-user-service.sh
systemctl --user enable --now secs-docs-portal.service
systemctl --user stop secs-docs-portal.service
systemctl --user status secs-docs-portal.service
Use systemctl --user start secs-docs-portal.service for a one-shot manual start after installation. The installer writes ~/.config/systemd/user/secs-docs-portal.service with absolute paths for this checkout and the current npm and Node binaries; rerun it if the repo path or Node install changes. While the user service is running, its lifecycle hook syncs the /secs mount via a shim to dev-setup (scripts/docs-portal-tailscale.sh). The landing menu script lives in dev-setup/machines/herki-pc-ubuntu/tailnet/landing.js and is started by scripts/run-docs-portal.sh. If Tailscale is missing, the loopback docs portal still starts and only route sync is skipped. Enable linger with loginctl enable-linger "$USER" if you need the user service without an interactive login.
Machine-wide routing (root menu, Endgate, Valenar, WebEngine dashboard, DMS/buildlog) is documented in dev-setup/shared/projects/dev-surfaces.md. Canonical manifest: dev-setup/machines/herki-pc-ubuntu/tailnet/manifest.json.
bash scripts/host-tailscale.sh apply # all projects (shim)
bash scripts/docs-portal-tailscale.sh enable # /secs only
bash scripts/run-docs-portal.sh run # local :4173, menu :4180
Private docs URL: https://<host>.ts.net/secs/docs/ (Docusaurus under /secs/). See dev-host/README.md and docs/project/pr-tailscale-host-routing.md.
| # | Document | What it covers |
|---|---|---|
| 00 | Overview | Lowering-contract entry point, glossary, reading order, diagnostic map |
| 01 | World Shape | Scope declarations, contracts, top-level channel declarations, the H.* hash convention |
| 02 | Templates | template<Contract> Name { }, fields, intrinsic/dynamic channels in templates, CanBuild, lifecycle methods, bare templates |
| 03 | Channels and Modifiers | Modifiers, formulas, triggers, 6-phase target resolution recap, reads {}, ValidateDependencies() |
| 04 | Behavior | Systems, events (pulse + player choices), on-actions, activities, policies |
| 05 | Expressions | Scope sigils (@this/@root/…), resolve/increment/add_modifier/fire/save_scope_as, foreach, query keywords (any/every/count/random/first) |
| 06 | Mod Operations and Modding | inject / replace operation model, load order, typed identity, FNV-1a identity, slot schema, AST-level merger, conflict detection |
| 07 | Structured Template Data and Callables | C# source type binding, generated SecsTypeRef metadata, structured template fields, typed query returns, feature placement query contract |
| 08 | Collections and Propagation | ScopedList<T>, ScopedDictionary<TKey,T>, TemplateId, tags, modifier propagation, previous-tick bridge reads, aggregate channels, system phase/frequency slots, registry-only recipes |
| 09 | AI Policies and Activities | Policies, utility-AI scoring, activities, runtime player slots, mod injection examples |
| 10 | Host <-> SECS execution boundary | Boundary classification + assembly placement |
| v2 | SECS v2 kernel rewrite ADR | Accepts the v2 architecture (Decisions 1–4, seven new assemblies) |
| v2 | Kernel + runtime layer architecture | Four-layer diagram (L1 SECS source → L4 kernel → L5 adapters) |
| v2 | Kernel contract | SecsKernel API, seven required relation kinds, determinism spec |
| v2 | WorldSchema contract | WorldSchema struct, every required row type, compiler-emit and kernel-consume contracts |
| v2 | Native collections and types | SECS.Native collection types; managed-backed initially; no Unity references |
| v2 | Save / load and determinism | SecsSavePayload, PortableRandom (xoshiro256**), golden replay test |
| v2 | External engine adapter contract | Adapter contract; Unity-hosted examples are adapters; six split bridges |
| — | Fork Decision | Roslyn fork vs source generator strategy |
| — | ADRs under docs/decisions/ and docs/adr/ | Architectural decisions that explain why the live design contract looks the way it does. Use alongside the numbered design docs when you need rationale rather than lowering detail. |
Key Concepts
- Templates define what entities ARE (static, contribute channels, lifecycle methods)
- Systems define what HAPPENS each tick (non-static, frequency-gated, phased)
- Events define what happens WHEN (pulse triggers, on_action hooks, player choices)
- Modifiers are reusable effect bundles that modify channel values
- Channels resolve through the implemented 6-phase target pipeline: base, additive, multiplicative, HardOverride, clamp, return.
- Formulas are dynamic channel contributions and modifier effects evaluated at resolution time
- Mod operations let layered content use
inject,replace,try inject,try replace,inject_or_create, andreplace_or_createagainst semantic slots. Activity/policy mods finalize at runtime startup; the full source-set merger for all declaration kinds is Phase 3 compiler work. Later writes win by load order, with conflicts reported for tooling.
Valenar Examples
The active Valenar track is Valenar v2, backed by examples/valenar-v2/Content, compiler-owned schema output under examples/valenar-v2/Generated/obj/**/SecsGenerated, retained explicit host-owned helpers, a v2 host/server, and the React/SignalR frontend. Missing or retired-empty v2 domains surface as empty/unavailable rather than faked; backed domains project real v2 host/runtime data. The map domain ships geometry + biomes + hierarchy from authored WorldData fixtures, authored forced Feature anchors materialize as real Feature entities, and ordinary score-and-budget Feature placement is retired by ADR. See examples/valenar-v2/README.md for the implementation status matrix.
Endgate Prototype
Endgate is a focused v2 prototype for host authority, deterministic map pressure, SignalR transport, a small React/Vite client, and benchmark coverage. It lives under examples/endgate/ with committed .secs content in Content/, compiler-owned schema output, and retained explicit host/catalog helpers under Generated/.
Building
dotnet build SECS.sln
Targets: netstandard2.1 (engine libraries, Unity-compatible), net8.0 (examples), and net10.0 for the Phase 1 compiler smoke. v2 test projects live at top-level tests/ (SECS.Core.Tests, SECS.Kernel.Tests, SECS.Native.Tests, SECS.Runtime.Tests, SECS.Schema.Tests, SECS.Standalone.Tests, SECS.Compiler.Smoke, Valenar.V2.Server.Tests, Endgate.Server.Tests); run SECS.Compiler.Smoke directly after building the Roslyn fork and tools/secsc.
For the production-core spine, run:
bash scripts/validate-production-core-spine.sh
That script runs runtime tests, Valenar server tests, Endgate server tests, and a full solution build. It supports split dotnet command selection through DOTNET_TEST and DOTNET_BUILD.
Running Valenar v2 (SignalR + React frontend)
examples/valenar-v2/Server is an ASP.NET Core SignalR hub at /gamehub wrapping the v2 runtime, and examples/valenar-v2/Client is the React/SignalR Valenar frontend pointed at that hub. Implementation status is matrix-tracked in examples/valenar-v2/README.md; empty domains stay empty rather than faked.
Server (SignalR hub on port 5063):
dotnet run --project examples/valenar-v2/Server
Client (Vite dev server on port 5173 with base: '/valenar/'; proxies /valenar/gamehub to the v2 server with WebSocket upgrade):
cd examples/valenar-v2/Client && npm install && npm run dev
Open http://localhost:5173/valenar/ in your browser.
Running Endgate
See examples/endgate/README.md for the subproject map, current prototype scope, server/client commands, the /gamehub SignalR endpoint, tests, benchmarks, and the Content/Generated provenance model.