diff --git a/profiles/sets/coding/agents/agents.nix b/profiles/sets/coding/agents/agents.nix index 6fc5f2c..af0e130 100644 --- a/profiles/sets/coding/agents/agents.nix +++ b/profiles/sets/coding/agents/agents.nix @@ -19,11 +19,14 @@ }; imports = [ - # OpenCode and Pi agent configurations + # OpenCode, Pi, and Babysitter agent configurations + ./babysitter.nix ./opencode.nix ./pi.nix ]; + coding.agents.babysitter.enable = true; + coding.agents.skills = { agentsInput = inputs.agents; externalSkills = [ diff --git a/profiles/sets/coding/agents/babysitter.nix b/profiles/sets/coding/agents/babysitter.nix new file mode 100644 index 0000000..12216df --- /dev/null +++ b/profiles/sets/coding/agents/babysitter.nix @@ -0,0 +1,142 @@ +# Babysitter user profile for Pi/agent workflows. +{ + config, + lib, + ... +}: let + cfg = config.coding.agents.babysitter; + defaultTimestamp = "2026-05-29T00:00:00.000Z"; + + defaultUserProfile = { + name = config.home.username; + specialties = [ + { + domain = "declarative-system-configuration"; + subdomains = ["nix" "home-manager" "agents"]; + } + ]; + expertiseLevels = {}; + goals = [ + { + id = "goal-agents-declarative-profile"; + description = "Keep Babysitter user preferences declarative and reproducible across systems."; + category = "agents"; + priority = "medium"; + status = "active"; + } + ]; + preferences = { + verbosity = "concise"; + autonomyLevel = "semi-autonomous"; + riskTolerance = "conservative"; + }; + toolPreferences = { + packageManagers = ["nix"]; + languages = ["nix"]; + operatingSystem = "nixos"; + }; + breakpointTolerance = { + global = "moderate"; + skipBreakpointsForKnownPatterns = false; + alwaysBreakOn = ["destructive-operations" "secrets" "external-publication"]; + }; + communicationStyle = { + tone = "technical"; + language = "en"; + useEmojis = false; + explanationDepth = "brief"; + preferredResponseFormat = "markdown"; + }; + experience = {}; + installedPlugins = ["babysitter-pi"]; + installedSkills = ["babysit" "call" "plan" "resume" "doctor" "yolo"]; + installedAgents = []; + createdAt = defaultTimestamp; + updatedAt = defaultTimestamp; + version = 1; + }; + + effectiveProfile = lib.recursiveUpdate cfg.profile cfg.profileOverrides; + profileJsonTarget = "${cfg.profileDirectory}/user-profile.json"; + profileMarkdownTarget = "${cfg.profileDirectory}/user-profile.md"; + profilePreferences = effectiveProfile.preferences or {}; + profileBreakpointTolerance = effectiveProfile.breakpointTolerance or {}; + + listMarkdown = values: + lib.concatMapStringsSep "\n" (value: "- ${toString value}") values; + + specialtyDomains = map (specialty: specialty.domain or "unspecified") (effectiveProfile.specialties or []); + + profileMarkdown = '' + # Babysitter User Profile + + This file is generated by Home Manager from `coding.agents.babysitter`. + + - Name: ${effectiveProfile.name or "unspecified"} + - Breakpoint tolerance: ${profileBreakpointTolerance.global or "unspecified"} + - Autonomy level: ${profilePreferences.autonomyLevel or "unspecified"} + - Risk tolerance: ${profilePreferences.riskTolerance or "unspecified"} + + ## Specialties + + ${listMarkdown specialtyDomains} + + ## Installed Babysitter Pi Skills + + ${listMarkdown (effectiveProfile.installedSkills or [])} + ''; +in { + options.coding.agents.babysitter = { + enable = lib.mkEnableOption "Babysitter user profile for Pi/agent workflows"; + + profileDirectory = lib.mkOption { + type = lib.types.str; + default = ".a5c"; + description = '' + Home-relative directory where Babysitter reads the user profile. + Babysitter Pi documents the user profile at ~/.a5c/user-profile.json. + ''; + }; + + profile = lib.mkOption { + type = lib.types.attrsOf lib.types.anything; + default = defaultUserProfile; + description = "Complete non-secret Babysitter user profile JSON."; + }; + + profileOverrides = lib.mkOption { + type = lib.types.attrsOf lib.types.anything; + default = {}; + description = '' + Recursive overrides merged into the default Babysitter user profile. + Keep this non-secret; the result is written into the Nix store. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = cfg.profileDirectory != "" && !lib.hasPrefix "/" cfg.profileDirectory; + message = "coding.agents.babysitter.profileDirectory must be a non-empty home-relative path."; + } + { + assertion = effectiveProfile ? name && builtins.isString effectiveProfile.name; + message = "coding.agents.babysitter profile must include a string name."; + } + { + assertion = effectiveProfile ? specialties && builtins.isList effectiveProfile.specialties; + message = "coding.agents.babysitter profile must include a specialties list."; + } + { + assertion = effectiveProfile ? breakpointTolerance && effectiveProfile.breakpointTolerance ? global; + message = "coding.agents.babysitter profile must include breakpointTolerance.global."; + } + ]; + + home.file = { + "${profileJsonTarget}".text = builtins.toJSON effectiveProfile + "\n"; + "${profileMarkdownTarget}".text = profileMarkdown; + }; + }; +}