using System.Text.Json.Serialization; namespace ClawdDotNet.Core.Config; public sealed class InstanceConfig { [JsonPropertyName("instanceId")] public string InstanceId { get; set; } = Guid.NewGuid().ToString("N")[..8]; [JsonPropertyName("instanceName")] public string InstanceName { get; set; } = "Default"; [JsonPropertyName("openRouterApiKey")] public string OpenRouterApiKey { get; set; } = ""; [JsonPropertyName("workingDirectory")] public string WorkingDirectory { get; set; } = "./data/"; /// /// Where this instance logs to. Empty means <Instanzverzeichnis>/Logs. /// /// Per instance and not application-wide (#528, stage 1). Previously, when /// "empty", the log directory from the application settings applied — one place for all /// instances. Startup.log then contained alternating lines of two instances /// without marking which one was speaking; in multi-instance operation every /// troubleshooting session was guesswork. /// /// A relative value is resolved against the instance directory, not against the /// working directory of the process (see AppHost.ResolveLogDirectory). /// [JsonPropertyName("logDirectory")] public string LogDirectory { get; set; } = ""; /// /// Whether the instance manager keeps this instance running (#528). /// /// Two things in one switch, because it is the same promise: the manager /// starts this instance when it comes up itself, and it starts it again when /// it crashes. Whoever does not want that leaves it off — then it only starts when someone /// asks for it. /// /// Pre-set to off, and that is the cautious side: a /// manager that boots everything it finds after a restart of the machine /// also starts what someone stopped on purpose. /// /// The restart after a crash is limited: after several attempts in /// quick succession the manager pauses and reports it. What fails because of a broken /// configuration fails the same way on the tenth attempt, and then instead /// of a dead instance you have a dead instance and a full log. /// [JsonPropertyName("autostartByManager")] public bool AutostartByManager { get; set; } /// /// Where the backups of this instance go. Empty means /// <Instanzverzeichnis>/Backups. /// /// Per instance (#528, stage 1). Previously the archives of all instances lay /// in one folder, and retention () cleans up there /// by the prefix backup_<Instanzname>_. If two names are nested /// in each other — Test and Test_2 —, one instance counts the archives /// of the other too and throws away the surplus ones. /// [JsonPropertyName("backupDirectory")] public string BackupDirectory { get; set; } = ""; /// Creates a backup of this instance daily at the configured time. [JsonPropertyName("autoBackupEnabled")] public bool AutoBackupEnabled { get; set; } /// Time of day of the automatic backup, HH:mm. [JsonPropertyName("autoBackupTime")] public string AutoBackupTime { get; set; } = "03:00"; /// /// How many backups of this instance are kept. 0 = keep all. /// [JsonPropertyName("backupKeepCount")] public int BackupKeepCount { get; set; } = 14; /// /// Port of the web UI. Goes away with the instance manager (E-M5): instances will /// listen exclusively on their socket/named pipe; the manager carries the web UI. /// /// Not yet [Obsolete]. The attribute was here briefly and produced /// six warnings without anyone being able to fix any of them — until E-M5 is /// completed, the port is the only way a standalone instance /// offers its user interface. A warning that only teaches looking away is /// worse than none; it comes back when the replacement is in place. /// [JsonPropertyName("webServerPort")] public int WebServerPort { get; set; } = 7001; /// /// Whether the web UI runs along. Pre-set to off — it turns a /// local application into a network service that controls agents with file, mail and /// FTP access. That is something you switch on deliberately. /// [JsonPropertyName("webUiEnabled")] public bool WebUiEnabled { get; set; } /// /// loopback (default) or any. With any /// is mandatory, otherwise the web UI does not start. /// [JsonPropertyName("webUiBinding")] public string WebUiBinding { get; set; } = "loopback"; /// /// Access token of the web UI. Listed in ConfigSecrets and thus stored /// protected in the instance file — like the OpenRouter key next to it. /// [JsonPropertyName("webUiToken")] public string WebUiToken { get; set; } = ""; [JsonPropertyName("telegramClient")] public TelegramClientConfig? TelegramClient { get; set; } /// Connection to the Deploymentcenter's watchdog module (instance heartbeat). [JsonPropertyName("watchdog")] public WatchdogConfig Watchdog { get; set; } = new(); /// Daily limits across all agents of the instance. 0 = no limit. [JsonPropertyName("budget")] public InstanceBudget Budget { get; set; } = new(); /// /// #660: How long prompt and response of every run are kept. Default for all agents; /// each agent can override it. /// [JsonPropertyName("promptHistory")] public Transcripts.PromptHistorySettings PromptHistory { get; set; } = new(); /// /// How many hand-offs a delegation chain may have at most (B8, #206). /// A→B is depth 1. The chain catches cycles itself; this value limits the /// relay A→B→C→D that nobody commissioned and that costs a full /// run at every step. /// /// Instance-wide and not per agent: a chain belongs to none of the participants. /// /// /// #689: Escalations and conflicts — how long the agents have to solve a case before a /// human is called, and how many escalations a unit may raise a day before they go /// straight to a human. /// [JsonPropertyName("cases")] public Cases.CaseSettings Cases { get; set; } = new(); /// #717: When unused budget is filled, and when a task counts as large. [JsonPropertyName("fillWork")] public Budget.FillWorkSettings FillWork { get; set; } = new(); /// #712: The Claude Code account the instance's claude-code agents run on. [JsonPropertyName("claudeCode")] public Runtimes.ClaudeCodeSettings ClaudeCode { get; set; } = new(); /// #646: When the board follows up on work that lives but does not move. [JsonPropertyName("followUp")] public Tasks.FollowUpSettings FollowUp { get; set; } = new(); /// #700: How long runs stay in the working database before they move to the month archive — nothing is deleted. [JsonPropertyName("auditArchive")] public Audit.AuditArchiveSettings AuditArchive { get; set; } = new(); /// #719: The history of the workspaces — on by default, 90 days. [JsonPropertyName("fileHistory")] public Files.FileHistorySettings FileHistory { get; set; } = new(); /// #726: Whether this instance works with n8n — only then do agents propose workflows. Off by default. [JsonPropertyName("automation")] public Automation.AutomationSettings Automation { get; set; } = new(); /// #197: External MCP servers whose tools the agents may use — set up by a human only. [JsonPropertyName("mcpServers")] public List McpServers { get; set; } = new(); /// #699: When a change in the units' costs is reported. [JsonPropertyName("costWatch")] public Accounting.CostWatchSettings CostWatch { get; set; } = new(); [JsonPropertyName("maxDelegationDepth")] public int MaxDelegationDepth { get; set; } = 3; /// /// How long a delegated call waits at most for a busy target agent, /// in seconds (#461). After that a refusal comes instead of further waiting. /// /// Applies only to delegations. A chat triggered by a human still queues /// up and waits as long as it takes. /// [JsonPropertyName("delegationGateTimeoutSeconds")] public int DelegationGateTimeoutSeconds { get; set; } = 120; /// /// #682: How many scheduled task runs may be in flight at the same time. Due tasks /// beyond this wait in order of priority and due time and start as soon as a run /// finishes. /// /// Why a cap at all. Cron expressions pile up on round times. Without a /// cap, fifty due tasks meant fifty simultaneous model calls — provider rate limits, /// a cost spike, and all fifty passing the instance budget check together, because /// that check runs per run before it starts. /// /// Per instance for now; per unit comes with #685. Values below 1 count as 1. /// A run the human starts by hand does not wait for a free slot, but it occupies one /// while it runs. /// [JsonPropertyName("maxParallelTaskRuns")] public int MaxParallelTaskRuns { get; set; } = 4; [JsonPropertyName("agents")] public List Agents { get; set; } = new(); /// /// #683: Departments, teams, groups — the organisation tree. Empty means no structure: /// every agent can reach every other, as before units existed. /// [JsonPropertyName("units")] public List Units { get; set; } = new(); /// /// #684: Shared workspaces with member lists — one per unit, plus those shared across /// units on purpose. The instance's one shared folder is not listed here; it stays the /// workspace shared, governed by each agent's level as before. /// [JsonPropertyName("workspaces")] public List Workspaces { get; set; } = new(); [JsonPropertyName("services")] public List Services { get; set; } = new(); } public sealed class TelegramClientConfig { [JsonPropertyName("apiId")] public int ApiId { get; set; } [JsonPropertyName("apiHash")] public string ApiHash { get; set; } = ""; [JsonPropertyName("phoneNumber")] public string PhoneNumber { get; set; } = ""; [JsonPropertyName("password2FA")] public string? Password2FA { get; set; } }