From e99b08c0da90a1276f02383910fecb24268bebec Mon Sep 17 00:00:00 2001 From: "Marcus (agent-cos)" Date: Tue, 12 May 2026 15:03:56 -0700 Subject: [PATCH] Initial setup: Nix flake wrapping Hermes Agent as Speckl SME MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - flake.nix wrapping github:NousResearch/hermes-agent - NixOS module (nix/nixosModules.nix) with Speckl-preset config: - Model: anthropic/claude-opus-4.6 - Memory + skill generation + user modeling enabled - Container mode for self-modification - Deep-merged with user overrides - documents/SOUL.md — Speckl domain expert persona - documents/AGENTS.md — workspace rules - documents/USER.md — user template - README.md with usage instructions --- .gitignore | 5 +++ LICENSE | 21 +++++++++ README.md | 103 +++++++++++++++++++++++++++++++++++++++++++ documents/AGENTS.md | 30 +++++++++++++ documents/SOUL.md | 39 ++++++++++++++++ documents/USER.md | 17 +++++++ flake.nix | 23 ++++++++++ nix/nixosModules.nix | 96 ++++++++++++++++++++++++++++++++++++++++ nix/packages.nix | 26 +++++++++++ 9 files changed, 360 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 documents/AGENTS.md create mode 100644 documents/SOUL.md create mode 100644 documents/USER.md create mode 100644 flake.nix create mode 100644 nix/nixosModules.nix create mode 100644 nix/packages.nix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fce3fca --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.hermes/ +result/ +__pycache__/ +*.pyc +.env diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..296ccc2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Scott Scoble + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..491a926 --- /dev/null +++ b/README.md @@ -0,0 +1,103 @@ +# hermes-speckl — Nix flake for Speckl SME Agent + +A pre-configured [Hermes Agent](https://github.com/NousResearch/hermes-agent) instance +purpose-built for the **Speckl** specification language ecosystem. + +## What this gives you + +One `nixos-rebuild switch` and you have a self-learning AI agent that: + +- Understands SpeckDL, the Dark Provenance model, and your compiler architecture +- Compounds expertise across every Speckl task (code review, spec writing, research) +- Runs as a hardened systemd service with declarative config +- Connects via Discord, Telegram, Slack, WhatsApp, or CLI +- Gets faster on recurring tasks the longer it runs + +## Usage + +Add to your system flake: + +```nix +# flake.nix +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + hermes-speckl.url = "github:sscoble/hermes-speckl"; + }; + + outputs = { nixpkgs, hermes-speckl, ... }: { + nixosConfigurations.your-host = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + hermes-speckl.nixosModules.speckl + ./configuration.nix + ]; + }; + }; +} +``` + +Then configure: + +```nix +# configuration.nix +{ config, ... }: { + services.hermes-speckl = { + enable = true; + + # Declarative config (deep-merged into cli-config.yaml) + settings = { + model.default = "anthropic/claude-opus-4.6"; + toolsets = [ "all" ]; + }; + + # LLM API keys (use sops-nix or agenix) + environmentFiles = [ config.sops.secrets."hermes-env".path ]; + }; +} +``` + +Apply: + +```bash +nixos-rebuild switch --flake .#your-host +systemctl status hermes-speckl +journalctl -u hermes-speckl -f +``` + +## What's pre-configured + +| Setting | Value | +|---|---| +| Model | `anthropic/claude-opus-4.6` (override via `settings.model.default`) | +| Memory | Enabled with skill generation + user modeling | +| Terminal | Local backend, 180s timeout | +| Context compression | On, 85% threshold, Gemini 3 Flash summarizer | +| Agent | 60 max turns, medium reasoning effort | +| Container mode | Enabled (agent can install packages for self-modification) | +| SOUL.md | Speckl domain expert persona (see `documents/SOUL.md`) | + +## Container mode + +The agent runs inside a persistent Ubuntu container with: + +- **Node 22** via NodeSource (for MCP servers, js tooling) +- **Python 3.12 venv** via uv (for pip installs, custom tools) +- **Writable Nix store** (bind-mounted from host) +- **Sudo access** for the agent user (self-modification) + +This means the agent can `npm i -g`, `pip install`, and modify its own +environment — essential for skill creation and tool discovery. + +## Development + +```bash +# Run directly +nix run github:sscoble/hermes-speckl -- setup + +# Or from a local clone +git clone https://os.scoble.me/forgejo/sscoble/hermes-speckl +cd hermes-speckl +nix build +./result/bin/hermes setup +``` diff --git a/documents/AGENTS.md b/documents/AGENTS.md new file mode 100644 index 0000000..9c63876 --- /dev/null +++ b/documents/AGENTS.md @@ -0,0 +1,30 @@ +# AGENTS.md — Speckl SME Workspace + +Your workspace root for Speckl operations. + +## Files you manage + +- `SOUL.md` — Your domain expertise persona (read this first, always) +- `USER.md` — Who you're working with +- `MEMORY.md` — Your long-term curated memory (you write this) +- `memory/YYYY-MM-DD.md` — Daily operational notes +- `skills/` — Hermes auto-generated skill files (compounded expertise) + +## Directory structure + +``` +workspace/ +├── SOUL.md ← read me first +├── USER.md ← human you serve +├── MEMORY.md ← what you've learned long-term +├── memory/ +│ └── YYYY-MM-DD.md +└── skills/ ← auto-generated by learning loop +``` + +## Rules + +1. Always read SOUL.md first in a new session. +2. Capture what matters in memory/. +3. Curate MEMORY.md from daily notes periodically. +4. Trust your skill library — it's built from real experience. diff --git a/documents/SOUL.md b/documents/SOUL.md new file mode 100644 index 0000000..5eab777 --- /dev/null +++ b/documents/SOUL.md @@ -0,0 +1,39 @@ +# SOUL.md — Speckl SME Agent Persona + +You are a **Speckl domain expert** — a self-learning specialist in the +Speckl specification language ecosystem. Your knowledge compounds over time. + +## Your Expertise + +- **SpeckDL** — The Speckl specification language. You understand its + grammar, semantics, and compilation to TypeScript + provenance artifacts. +- **Dark Provenance** — Speckl's model for embedding provenance + requirements directly into specifications via §3.6 semantics. +- **Compilation manifest** — The dual BOM (Bill of Materials) that Speckl + produces: one for the software itself, one for provenance artifacts. +- **Spec as source of truth** — The core insight: AI generates code at + machine speed, humans own specifications, and SpeckDL is the shared space + where both can work. + +## Your Style + +- **Precise** — SpeckDL is formal. Your descriptions should be equally clean. +- **Concise** — Say what matters. Don't bury the signal. +- **Judgment-aware** — You write specs for humans to review. Frame things + so a person can say "yes, this captures my intent." +- **Compiled, not generated** — The Speckl compiler is deterministic. + No LLM in the compilation path. Same spec, same output. Always. + +## How You Learn + +- After completing a Speckl task, enter your reflective phase. +- Extract reusable patterns as Hermes skill files. +- The more Speckl work you do, the better you get at it. +- Build a persistent model of how this user prefers specs written. +- Never stop compounding. + +## Key References + +- Speckl repo: https://os.scoble.me/forgejo/sscoble/speckl +- SpeckDL spec: SPEC.md in the repo +- Dark Provenance whitepaper: docs/dark-provenance-whitepaper.md diff --git a/documents/USER.md b/documents/USER.md new file mode 100644 index 0000000..d3dc951 --- /dev/null +++ b/documents/USER.md @@ -0,0 +1,17 @@ +# USER.md — Speckl SME Agent User + +This file describes the human or team this Speckl SME agent serves. + +**(Fill this in when you set up the agent.)** + +## Example + +```markdown +# USER.md + +- **Name:** Scott Scoble +- **Pronouns:** he/him +- **Timezone:** US Eastern (EDT) +- **Role:** CEO, Greybeard Holdings / Speckl creator +- **Prefers:** Concise, precise specs. Semicolons, not em dashes. +``` diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..01e64dd --- /dev/null +++ b/flake.nix @@ -0,0 +1,23 @@ +{ + description = "Hermes Agent pre-configured as a self-learning Speckl SME"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-parts = { + url = "github:hercules-ci/flake-parts"; + inputs.nixpkgs-lib.follows = "nixpkgs"; + }; + hermes-agent = { + url = "github:NousResearch/hermes-agent"; + }; + }; + + outputs = inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } { + systems = [ "x86_64-linux" "aarch64-linux" ]; + + imports = [ + ./nix/packages.nix + ./nix/nixosModules.nix + ]; + }; +} diff --git a/nix/nixosModules.nix b/nix/nixosModules.nix new file mode 100644 index 0000000..d78ed24 --- /dev/null +++ b/nix/nixosModules.nix @@ -0,0 +1,96 @@ +{ inputs, ... }: +{ + flake.nixosModules.speckl = { config, lib, pkgs, ... }: + let + hermes = inputs.hermes-agent.nixosModules.default; + in { + imports = [ hermes ]; + + options.services.hermes-speckl = with lib; { + enable = mkEnableOption "Speckl SME agent (Hermes-based)"; + + settings = mkOption { + type = types.attrs; + default = { }; + description = "Hermes config overrides. Deep-merged with Speckl defaults."; + }; + + environmentFiles = mkOption { + type = types.listOf types.path; + default = [ ]; + description = "Paths to env files with API keys."; + }; + + environment = mkOption { + type = types.attrsOf types.str; + default = { }; + description = "Non-secret environment variables."; + }; + + addToSystemPackages = mkOption { + type = types.bool; + default = true; + description = "Add hermes CLI to system PATH."; + }; + + extraPackages = mkOption { + type = types.listOf types.package; + default = [ ]; + description = "Extra packages for the agent."; + }; + }; + + config = lib.mkIf config.services.hermes-speckl.enable { + # Map hermes-speckl service config to upstream hermes-agent service + services.hermes-agent = { + enable = true; + addToSystemPackages = config.services.hermes-speckl.addToSystemPackages; + environmentFiles = config.services.hermes-speckl.environmentFiles; + environment = config.services.hermes-speckl.environment; + container.enable = true; + extraPackages = config.services.hermes-speckl.extraPackages; + + # Speckl-preset default settings (deep-merged with user overrides) + settings = lib.recursiveUpdate { + model = { + default = "anthropic/claude-opus-4.6"; + base_url = "https://openrouter.ai/api/v1"; + }; + + terminal = { + backend = "local"; + timeout = 180; + }; + + agent = { + max_turns = 60; + reasoning_effort = "medium"; + }; + + memory = { + memory_enabled = true; + skill_generation = true; + user_profile_enabled = true; + memory_char_limit = 4000; + nudge_interval = 10; + }; + + compression = { + enabled = true; + threshold = 0.85; + summary_model = "google/gemini-3-flash-preview"; + }; + + toolsets = [ "all" ]; + } config.services.hermes-speckl.settings; + + # Speckl workspace documents + documents = { + "SOUL.md" = builtins.readFile ./documents/SOUL.md; + "AGENTS.md" = builtins.readFile ./documents/AGENTS.md; + "USER.md" = builtins.readFile ./documents/USER.md; + }; + }; + }; + }; +} diff --git a/nix/packages.nix b/nix/packages.nix new file mode 100644 index 0000000..dbf6356 --- /dev/null +++ b/nix/packages.nix @@ -0,0 +1,26 @@ +{ inputs, ... }: +{ + flake.packages = forAllSystems (system: + let + pkgs = inputs.nixpkgs.legacyPackages.${system}; + in { + default = inputs.hermes-agent.packages.${system}.default; + + speckl-config = pkgs.writeTextDir "speckl-config.yaml" '' + # Speckl SME — generated config + # Override via services.hermes-speckl.settings + model: + default: "anthropic/claude-opus-4.6" + memory: + memory_enabled: true + skill_generation: true + user_profile_enabled: true + toolsets: + - all + ''; + } + ); + + # Helper: build for the standard platforms + forAllSystems = inputs.nixpkgs.lib.genAttrs [ "x86_64-linux" "aarch64-linux" ]; +}