CoreAI does not ship game-specific configs. Instead, the core provides generic infrastructure to read/write JSON configs through AI function calling.
┌─────────────────────────────────────────────────────────┐
│ CoreAI (generic) │
│ ┌─────────────────┐ ┌──────────────┐ │
│ │ IGameConfigStore│ │ GameConfig │ │
│ │ (interface) │◄───│ Tool (ILlm) │ │
│ └────────┬────────┘ └──────────────┘ │
│ │ ▲ │
│ │ AI function calling │
└───────────┼────────────────────┼────────────────────────┘
│ │
┌──────┴──────┐ ┌───────┴───────┐
│ Your game │ │ LLM (Creator)│
│ implements │ │ read/update │
│ interface │ │ JSON configs │
└─────────────┘ └───────────────┘
| Component | Purpose | Where |
|---|---|---|
IGameConfigStore |
Interface: TryLoad(key), TrySave(key, json) |
CoreAI |
GameConfigTool |
ILlmTool for AI function calling (read/update) |
CoreAI |
GameConfigPolicy |
Which roles may read/write which keys | CoreAI |
UnityGameConfigStore |
ScriptableObject implementation | CoreAIUnity |
- Creates a ScriptableObject with parameters
- Registers it in
UnityGameConfigStore - Configures
GameConfigPolicyfor roles - AI accesses configs through function calling
// Assets/_exampleGame/Config/GameSessionConfig.cs
using UnityEngine;
[CreateAssetMenu(menuName = "MyGame/Session Config")]
public class GameSessionConfig : ScriptableObject
{
[Range(0, 3)] public int Difficulty = 1;
[Range(0.1f, 10f)] public float EnemyHealthMultiplier = 1f;
[Range(0.1f, 10f)] public float EnemyDamageMultiplier = 1f;
[Range(1, 500)] public int MaxActiveEnemies = 50;
}// In your LifetimeScope:
var configStore = container.Resolve<UnityGameConfigStore>();
configStore.Register("session", mySessionConfigAsset);
// Configure policy
var configPolicy = container.Resolve<GameConfigPolicy>();
configPolicy.SetKnownKeys(new[] { "session", "crafting" });
configPolicy.GrantFullAccess("Creator"); // Creator can do everything
configPolicy.ConfigureRole("CoreMechanicAI",
readKeys: new[] { "session" },
writeKeys: new[] { "session" });AiOrchestrator automatically passes GameConfigTool to the LLM when:
- The role has config access (via
GameConfigPolicy) AgentMemoryPolicy.GetToolsForRole()includes GameConfigTool
// In AiOrchestrator — tools are assembled automatically:
var tools = _memoryPolicy?.GetToolsForRole(roleId);
// GameConfigTool is added separately if the role has access
if (_configPolicy.GetAllowedKeys(roleId).Length > 0)
{
var configTool = _configPolicy.CreateLlmTool(_configStore, roleId);
tools.Add(configTool.CreateAIFunction());
}// AI function call:
{
"name": "game_config",
"arguments": {
"action": "read"
}
}
// Response:
{
"success": true,
"message": "Config read successfully",
"config_json": "{\"session\":{\"difficulty\":1,\"enemy_hp_mult\":1.0}}"
}// AI function call with modified JSON:
{
"name": "game_config",
"arguments": {
"action": "update",
"content": "{\"difficulty\":2,\"enemy_hp_mult\":1.5,\"max_enemies\":80}"
}
}
// Confirmation:
{
"success": true,
"message": "Config updated for key: session"
}// Restrict role access:
configPolicy.ConfigureRole("AINpc",
readKeys: new[] { "dialogue" }, // Read only
writeKeys: Array.Empty<string>()); // No write
configPolicy.RevokeAccess("SmartChat"); // No access// EditMode test
[Test]
public void ConfigTool_ReadModifyWrite_Works()
{
var store = new InMemoryConfigStore();
store.Save("session", "{\"difficulty\":1}");
var policy = new GameConfigPolicy();
policy.GrantFullAccess("Creator");
var tool = new GameConfigTool(store, policy, "Creator");
// Read
var readResult = tool.ExecuteAsync("read").Result;
Assert.IsTrue(readResult.Success);
// Update
var writeResult = tool.ExecuteAsync("update", "{\"difficulty\":3}").Result;
Assert.IsTrue(writeResult.Success);
// Verify
store.TryLoad("session", out var json);
Assert.IsTrue(json.Contains("3"));
}CoreAI (portable):
├── Features/Config/
│ ├── IGameConfigStore.cs # Interface
│ ├── GameConfigTool.cs # ILlmTool
│ ├── GameConfigPolicy.cs # Access policy
│ ├── GameConfigLlmTool.cs # ILlmTool wrapper
│ └── NullGameConfigStore.cs # Stub
CoreAIUnity (Unity):
├── Features/Config/Infrastructure/
│ └── UnityGameConfigStore.cs # ScriptableObject implementation
Your game:
├── Config/
│ ├── GameSessionConfig.cs # Your ScriptableObject
│ ├── GameSessionConfig.asset # Asset
│ └── ConfigInstaller.cs # DI registration
- ScriptableObject with parameters created
- Config asset created (
CreateAssetMenu) -
UnityGameConfigStore.Register("key", configAsset)called -
GameConfigPolicyconfigured for roles - AI system prompt mentions available keys
- Tests written (EditMode + PlayMode)
- One key = one ScriptableObject — do not mix unrelated config types
- Validate on the SO — use
[Range]to block absurd values - Logging —
UnityGameConfigStorelogs all changes - Editor — changes persist to the asset via
EditorUtility.SetDirty - Runtime — in builds, changes last until scene reload