using System.Text.Json;using System.Text.RegularExpressions;using Agent.Core;namespace Lilith.Agent.SelfImprovement;/// <summary>Persists the tool-under-test spec for self-improvement smoke runs (edit scenario step 1 only).</summary>internal sealed class ToolSpecStore{ public const string FileName = "self-improvement-tool-spec.json"; public string ToolName { get; set; } = ""; public string Description { get; set; } = ""; public string Category { get; set; } = "self"; public string InvokeBody { get; set; } = "return \"OK\";"; public string ExpectedResult { get; set; } = ""; public static string GetSpecPath(Workspace workspace) => Path.Combine(workspace.ConfigFolder, FileName); public static ToolSpecStore Load(Workspace workspace) { string path = GetSpecPath(workspace); if (!File.Exists(path)) return new ToolSpecStore(); string json = File.ReadAllText(path); return JsonSerializer.Deserialize<ToolSpecStore>(json, JsonOptions) ?? new ToolSpecStore(); } public void Save(Workspace workspace) { Directory.CreateDirectory(workspace.ConfigFolder); File.WriteAllText(GetSpecPath(workspace), JsonSerializer.Serialize(this, JsonOptions)); } public static ToolSpecStore ParseFromJson(string argumentsJson) { using var doc = JsonDocument.Parse(string.IsNullOrWhiteSpace(argumentsJson) ? "{}" : argumentsJson); var root = doc.RootElement; return new ToolSpecStore { ToolName = GetString(root, "tool_name", "name", "tool"), Description = GetString(root, "description", "desc"), Category = GetString(root, "category", "cat") is { Length: > 0 } c ? c : "self", InvokeBody = GetString(root, "invoke_body", "invokeBody", "body"), ExpectedResult = GetString(root, "expected_result", "expectedResult", "expected"), }; } /// <summary>Expected tool return value for smoke invoke checks (explicit or parsed from invoke_body).</summary> public string? ResolveExpectedResult() { if (!string.IsNullOrWhiteSpace(ExpectedResult)) return ExpectedResult.Trim(); return TryParseReturnLiteral(InvokeBody); } public static string? TryParseReturnLiteral(string? invokeBody) { if (string.IsNullOrWhiteSpace(invokeBody)) return null; var match = Regex.Match(invokeBody.Trim(), @"return\s+""([^""]*)""\s*;?", RegexOptions.IgnoreCase); return match.Success ? match.Groups[1].Value : null; } public void MergeMissing(ToolSpecStore other) { if (string.IsNullOrWhiteSpace(ToolName) && !string.IsNullOrWhiteSpace(other.ToolName)) ToolName = other.ToolName; if (string.IsNullOrWhiteSpace(Description) && !string.IsNullOrWhiteSpace(other.Description)) Description = other.Description; if (string.IsNullOrWhiteSpace(Category) && !string.IsNullOrWhiteSpace(other.Category)) Category = other.Category; if (string.IsNullOrWhiteSpace(InvokeBody) && !string.IsNullOrWhiteSpace(other.InvokeBody)) InvokeBody = other.InvokeBody; } public bool IsComplete => !string.IsNullOrWhiteSpace(ToolName) && !string.IsNullOrWhiteSpace(Description) && !string.IsNullOrWhiteSpace(Category); private static string GetString(JsonElement root, params string[] names) { foreach (string name in names) { if (root.TryGetProperty(name, out var el)) { string? s = el.GetString(); if (!string.IsNullOrWhiteSpace(s)) return s.Trim(); } } return ""; } private static readonly JsonSerializerOptions JsonOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true, };}
Documentation
Lilith self-improvement (Version 7+)
Lilith can extend herself only by creating tools in three categories:
| Category | Location | Examples | |----------|----------|----------| | Core | Agent-Core | Memory, time (rare; system-level) | | Addon | Agent-Addons | Weather, C# projects, apps | | Self | Lilith | Workspace files, self-improvement |
Layout
ShippedSource/— copy ofsrc/Version7next to the built app (MSBuildCopyShippedSource){workspace}/output/self-improvement/live— current editable source{workspace}/output/self-improvement/sandbox— clone for edits and builds{workspace}/output/self-improvement/backups/{timestamp}— backups before promote
Tools
1. self_improve_get_source_layout 2. self_improve_generate_tool 3. self_improve_backup_live 4. self_improve_create_sandbox 5. self_improve_build_sandbox 6. self_improve_verify_sandbox_tool 7. self_improve_promote_sandbox — copies sandbox → live, builds, restarts
Set GENESIS_REPO_ROOT to the repo root when developing from source instead of ShippedSource.