diff --git a/.gitignore b/.gitignore index c89e06d3..0facf8bc 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,8 @@ tasks-archived-sheets/ tasks-sheets-verified/ tasks-sheets/ -dev/ \ No newline at end of file +dev/ +.cursor/rules/jcodemunch.mdc +uv.lock + +/.vs diff --git a/README.md b/README.md index 1d7fcd11..3aface68 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@

- - thirdlayer - + open-autoagent

@@ -66,6 +64,88 @@ rm -rf jobs; mkdir -p jobs && uv run harbor run -p tasks/ --task-name " run.log 2>&1 ``` +## Install quickly with an AI harness + +The `setup/` folder installs a skill that lets your AI harness run the full +Ollama setup for you — clone, `.env`, `uv sync`, Docker base image, Harbor +smoke test. + +```bash +# Linux / macOS / Git Bash +bash setup/install.sh + +# Windows PowerShell +.\setup\install.ps1 +``` + +Pick your harness when prompted, then trigger it: + +| Harness | Trigger | +|---|---| +| Hermes | New session (or `/reset`) → `run open-autoagent-ollama-setup` | +| Claude Code | In chat: `run open-autoagent-ollama-setup` | +| Claude Desktop | In chat: `run open-autoagent-ollama-setup` | +| Cursor | In chat: `run open-autoagent-ollama-setup` | +| Grok | In chat: `run open-autoagent-ollama-setup` | +| VS Code + Copilot | `Ctrl+Shift+I` → `#file:.vscode/skills/open-autoagent-ollama-setup/SKILL.md` → `run open-autoagent-ollama-setup` | +| Visual Studio | `View > GitHub Copilot Chat` → `#file:.github/skills/open-autoagent-ollama-setup/SKILL.md` → `run open-autoagent-ollama-setup` | + +The harness will execute every step and stop if a check fails. + +## Multi-LLM Support + +The harness supports multiple LLM providers via [LiteLLM](https://github.com/BerriAI/litellm). Configure via environment variables: + +### Environment Variables + +- `LLM_PROVIDER`: Provider name (`openai`, `anthropic`, `ollama`, `azure`, etc.) +- `MODEL`: Model name (e.g., `gpt-5`, `claude-3-5-sonnet`, `qwen3.5:35b-a3b-q8_0`) +- `LLM_BASE_URL`: Optional base URL (required for Ollama, Azure, etc.) +- `API_KEY`: Provider-specific API key (e.g., `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) + +### Using Local Ollama + +```bash +cat > .env << 'EOF' +LLM_PROVIDER=ollama +MODEL=qwen3.5:35b-a3b-q8_0 +LLM_BASE_URL=http://host.docker.internal:11434/v1 +EOF +``` + +### Using OpenAI + +```bash +cat > .env << 'EOF' +LLM_PROVIDER=openai +MODEL=gpt-5 +OPENAI_API_KEY=your-api-key +EOF +``` + +### Using Anthropic + +```bash +cat > .env << 'EOF' +LLM_PROVIDER=anthropic +MODEL=claude-3-5-sonnet +ANTHROPIC_API_KEY=your-api-key +EOF +``` + +### Using Azure + +```bash +cat > .env << 'EOF' +LLM_PROVIDER=azure +MODEL=your-deployment-name +AZURE_API_KEY=your-api-key +AZURE_API_BASE=https://your-resource.openai.azure.com +EOF +``` + +The model selection is optional and can be changed dynamically by modifying the environment variables before running the benchmark. + ## Running the meta-agent Point your coding agent at the repo and prompt: @@ -153,4 +233,3 @@ You can equip the agent with [Agent Skills for Context Engineering](https://gith ## License MIT - diff --git a/agent.py b/agent.py index d155db41..b104b6bd 100644 --- a/agent.py +++ b/agent.py @@ -26,8 +26,18 @@ # ============================================================================ SYSTEM_PROMPT = "You are an agent that executes tasks" -MODEL = "gpt-5" -MAX_TURNS = 30 +MAX_TURNS = 15 + +# Multi-LLM configuration via LiteLLM +# Set environment variables before running: +# - LLM_PROVIDER: "openai", "anthropic", "ollama", "azure", etc. +# - MODEL: model name (e.g., "gpt-5", "claude-3-5-sonnet", "qwen3.5:35b-a3b-q8_0") +# - LLM_BASE_URL: optional base URL (required for Ollama, Azure, etc.) +# - API_KEY: provider-specific API key (e.g., OPENAI_API_KEY, ANTHROPIC_API_KEY) +import os +LLM_PROVIDER = os.getenv("LLM_PROVIDER", "openai").lower() +MODEL = os.getenv("MODEL", "gpt-5") +LLM_BASE_URL = os.getenv("LLM_BASE_URL") def create_tools(environment: BaseEnvironment) -> list[FunctionTool]: @@ -53,11 +63,25 @@ async def run_shell(command: str) -> str: def create_agent(environment: BaseEnvironment) -> Agent: """Build the agent. Modify to add handoffs, sub-agents, or agent-as-tool.""" tools = create_tools(environment) + + # Build LiteLLM-compatible model string + if LLM_PROVIDER == "ollama": + # Ollama uses custom base URL format + model_string = f"ollama_chat/{MODEL}" if not LLM_BASE_URL else f"ollama_chat/{MODEL}" + elif LLM_PROVIDER == "azure": + # Azure uses deployment name format + model_string = f"azure/{MODEL}" + elif LLM_PROVIDER == "anthropic": + model_string = f"anthropic/{MODEL}" + else: + # Default to OpenAI format + model_string = MODEL + return Agent( name="autoagent", instructions=SYSTEM_PROMPT, tools=tools, - model=MODEL, + model=model_string, ) diff --git a/docs/logo.png b/docs/logo.png new file mode 100644 index 00000000..f63ddddc Binary files /dev/null and b/docs/logo.png differ diff --git a/pyproject.toml b/pyproject.toml index c419b630..df8ceb72 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,4 +9,5 @@ dependencies = [ "openpyxl", "numpy", "harbor", + "litellm>=1.60.0", ] diff --git a/setup/.gitignore b/setup/.gitignore new file mode 100644 index 00000000..9607b875 --- /dev/null +++ b/setup/.gitignore @@ -0,0 +1 @@ +.skill-config.json diff --git a/setup/.skill-config.json.example b/setup/.skill-config.json.example new file mode 100644 index 00000000..994fc447 --- /dev/null +++ b/setup/.skill-config.json.example @@ -0,0 +1,17 @@ +{ + "mainRepo": "https://github.com/Oncorporation/open-autoagent", + "domainRepo": "https://github.com/Oncorporation/secure-torrent-mcp-agent", + "domainBranch": "domain/secure-torrent", + "llmProvider": "ollama", + "model": "qwen3.8:27b-mtp-q8_0", + "ollamaEndpoint": "http://127.0.0.1:11434", + "hardware": "AMD Ryzen AI Max+ 395 64GB-64GB", + "skillMetadata": { + "name": "open-autoagent-ollama-setup", + "description": "Set up Oncorporation open-autoagent on a host-native Ollama daemon for Harbor harness experiments.", + "license": "MIT", + "version": "1.0.0", + "hermesTags": ["open-autoagent", "ollama", "harbor", "harness"], + "hermesCategory": "mcp-install" + } +} diff --git a/setup/SETUP_WORKFLOW.md b/setup/SETUP_WORKFLOW.md new file mode 100644 index 00000000..71cfd073 --- /dev/null +++ b/setup/SETUP_WORKFLOW.md @@ -0,0 +1,77 @@ +# Setup Workflow + +The setup folder now supports **generic repository setup** via optional configuration. + +## Workflow + +### Option 1: Quick Start (Default) +Use the original hardcoded repo, model, and settings: + +```bash +# Linux / macOS +bash setup/install.sh + +# Windows PowerShell +.\setup\install.ps1 +``` + +Pick your harness, install, done. Defaults: +- Repo: `https://github.com/Oncorporation/open-autoagent` +- Model: `qwen3.8:27b-mtp-q8_0` +- Ollama: `http://127.0.0.1:11434` + +### Option 2: Custom Configuration +Use your own repo, model, hardware, LLM provider: + +```bash +# 1. Configure +bash setup/configure.sh # Linux/macOS +.\setup\configure.ps1 # Windows + +# 2. Install +bash setup/install.sh # Linux/macOS +.\setup\install.ps1 # Windows +``` + +The installer checks for `.skill-config.json` and uses it to customize the +SKILL.md before copying. If no config exists, defaults are used. + +## What Gets Configured + +| Setting | Purpose | Default | +|---|---|---| +| Main repo | GitHub/HF/local path to clone | `https://github.com/Oncorporation/open-autoagent` | +| Domain repo | Optional catalog/context repo | `https://github.com/Oncorporation/secure-torrent-mcp-agent` | +| Domain branch | Branch name in main repo | `domain/secure-torrent` | +| LLM provider | `ollama`, `openai`, `anthropic`, `azure` | `ollama` | +| Model | Model name/tag | `qwen3.8:27b-mtp-q8_0` | +| Ollama endpoint | Only if provider=ollama | `http://127.0.0.1:11434` | +| Hardware | Info string (notes only) | `AMD Ryzen AI Max+ 395 64GB-64GB` | + +## How It Works + +1. **`configure.sh/.ps1`** → prompts → saves to `.skill-config.json` +2. **`install.sh/.ps1`** → reads config (or defaults) → processes `SKILL.md.template` → installs customized SKILL.md +3. **Harness triggers** → runs the skill with custom repo/model/hardware baked in + +`.skill-config.json` is gitignored so it never gets committed. + +## Adding a New Harness + +1. Create `setup/harness/new-harness/` directory +2. **Either:** + - Pre-build: copy `SKILL.md.template` → `new-harness/SKILL.md` (installers will use it as-is) + - Or: install will auto-generate from template + config +3. Update installer menu (both `.sh` and `.ps1`) with harness option and trigger instructions +4. Done — installers pick up the new folder automatically + +## Files + +| File | Purpose | +|---|---| +| `configure.sh` / `configure.ps1` | Prompt user for custom config → save to `.skill-config.json` | +| `install.sh` / `install.ps1` | Read config (or defaults) → process template → install to harness | +| `SKILL.md.template` | Generic skill template with `{{PLACEHOLDERS}}` | +| `.skill-config.json` | User config (created by configure, gitignored) | +| `harness/*/SKILL.md` | Pre-built harness-specific skills (optional) | +| `open-autoagent-ollama-setup.md` | Legacy canonical skill (fallback only) | diff --git a/setup/SKILL.md.template b/setup/SKILL.md.template new file mode 100644 index 00000000..7fc08877 --- /dev/null +++ b/setup/SKILL.md.template @@ -0,0 +1,180 @@ +#!/usr/bin/env bash +# SKILL.md.template — Template for open-autoagent-ollama-setup skill +# +# This file is processed by install.sh to inject custom repo/model/hardware info. +# Placeholders: {{MAIN_REPO}}, {{DOMAIN_REPO}}, {{DOMAIN_BRANCH}}, {{MODEL}}, {{OLLAMA_ENDPOINT}}, {{HARDWARE}} + +--- +name: open-autoagent-ollama-setup +description: Set up {{MAIN_REPO}} on {{HARDWARE}}. Use when the user says set up open-autoagent, wire Ollama into AutoAgent, run Harbor, or work with the domain branch. Do not use for torrent MCP or download-orchestrator only. +license: MIT +metadata: + hermes: + tags: + - open-autoagent + - ollama + - harbor + - harness + category: mcp-install + version: "1.0.0" + hardware: {{HARDWARE}} + model: {{MODEL}} +--- + +# Set up open-autoagent on host-native Ollama + +You are running this procedure on the operator machine. Execute the steps +in order. Stop on the first failed check. + +## Locked settings from the project session + +| Key | Value | +|---|---| +| Repo | `{{MAIN_REPO}}` | +| Domain catalog | `{{DOMAIN_REPO}}` | +| Domain branch | `{{DOMAIN_BRANCH}}` | +| LLM provider | `ollama` | +| Model tag | `{{MODEL}}` | +| Ollama bind | `{{OLLAMA_ENDPOINT}}` | +| Hardware | {{HARDWARE}} | + +## Preconditions + +1. Workspace parent. Default `~/src`. +2. Confirm Ollama is installed and model `{{MODEL}}` is pulled. +3. Confirm Docker Desktop or Engine is installed. +4. Confirm `git`, `curl`, and Python 3.10+ exist. + +## Step 1 — host toolchain + +Run and record output. + +\`\`\`bash +uname -a +command -v git +command -v curl +command -v python3 +command -v docker +command -v uv || true +command -v ollama +ollama --version +docker version --format '{{.Server.Version}}' 2>/dev/null || docker version +\`\`\` + +Install uv if missing: + +\`\`\`bash +curl -LsSf https://astral.sh/uv/install.sh | sh +export PATH="$HOME/.local/bin:$PATH" +\`\`\` + +Fail if \`ollama\` or \`docker\` is missing. + +## Step 2 — native Ollama health + +\`\`\`bash +curl -sf {{OLLAMA_ENDPOINT}}/api/tags >/tmp/ollama-tags.json +python3 - << 'PY' +import json +tags = json.load(open("/tmp/ollama-tags.json")) +names = [m.get("name") for m in tags.get("models", [])] +print("models:", names) +need = "{{MODEL}}" +ok = any(n == need or n.startswith(need) for n in names) +print("have_target:", ok) +raise SystemExit(0 if ok else 2) +PY +\`\`\` + +If the model is missing: + +\`\`\`bash +ollama pull {{MODEL}} +\`\`\` + +## Step 3 — clone repos + +\`\`\`bash +SRC="${SRC:-$HOME/src}" +mkdir -p "$SRC" +cd "$SRC" + +git clone {{MAIN_REPO}}.git open-autoagent +git clone {{DOMAIN_REPO}}.git secure-torrent-mcp-agent +cd "$SRC/open-autoagent" +git checkout main && git pull +git checkout -b {{DOMAIN_BRANCH}} || git checkout {{DOMAIN_BRANCH}} + +mkdir -p vendor docs/domain +rsync -a --delete --exclude .git "$SRC/secure-torrent-mcp-agent/" vendor/secure-torrent-mcp-agent/ +\`\`\` + +## Step 4 — write \`.env\` + +\`\`\`bash +cd "$SRC/open-autoagent" +cat > .env << 'EOF' +LLM_PROVIDER=ollama +MODEL={{MODEL}} +LLM_BASE_URL={{OLLAMA_ENDPOINT}} +OLLAMA_API_BASE={{OLLAMA_ENDPOINT}} +EOF + +if ! grep -q '^\.env$' .gitignore 2>/dev/null; then + printf '\n.env\nresults.tsv\njobs/\nrun.log\n' >> .gitignore +fi + +set -a && . ./.env && set +a +\`\`\` + +## Step 5 — Python env and Docker base image + +\`\`\`bash +cd "$SRC/open-autoagent" +uv sync +docker build -f Dockerfile.base -t autoagent-base . +\`\`\` + +Confirm the agent module imports: + +\`\`\`bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +uv run python - << 'PY' +import os +print("LLM_PROVIDER", os.environ.get("LLM_PROVIDER")) +print("MODEL", os.environ.get("MODEL")) +print("LLM_BASE_URL", os.environ.get("LLM_BASE_URL")) +import agent +print("import_ok") +PY +\`\`\` + +## Step 6 — first Harbor run (baseline) + +\`\`\`bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +rm -rf jobs +mkdir -p jobs +uv run harbor run -p tasks/ -l 1 -n 1 \ + --agent-import-path agent:AutoAgent -o jobs --job-name latest \ + > run.log 2>&1 || true +\`\`\` + +Check output: + +\`\`\`bash +tail -n 40 run.log +ls jobs | head +\`\`\` + +## Done + +The setup is complete when: +- Ollama returns the model tag +- Docker base image built successfully +- Agent module imports with the correct provider and model +- At least one Harbor command ran (even if tasks don't exist yet) + +Next: Point a coding agent at \`program.md\` to run experiments. diff --git a/setup/configure.ps1 b/setup/configure.ps1 new file mode 100644 index 00000000..cc260b62 --- /dev/null +++ b/setup/configure.ps1 @@ -0,0 +1,87 @@ +#Requires -Version 5.1 +<# +.SYNOPSIS + Configure setup options for the open-autoagent-ollama-setup skill. +.DESCRIPTION + Interactively collects repository, model, and hardware information, + then generates a customized SKILL.md template. Run this BEFORE install.ps1 + if you want to use a custom repo, model, or hardware profile. + + Output: setup/.skill-config.json (gitignored, used by install.ps1) +.EXAMPLE + .\setup\configure.ps1 +#> + +$ErrorActionPreference = "Stop" + +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$ConfigFile = Join-Path $ScriptDir ".skill-config.json" + +# Defaults (sensible for the original use case) +$defaults = @{ + mainRepo = "https://github.com/Oncorporation/open-autoagent" + domainRepo = "https://github.com/Oncorporation/secure-torrent-mcp-agent" + domainBranch = "domain/secure-torrent" + llmProvider = "ollama" + model = "qwen3.8:27b-mtp-q8_0" + ollamaEndpoint = "http://127.0.0.1:11434" + hardware = "AMD Ryzen AI Max+ 395 64GB-64GB" +} + +Write-Host "" +Write-Host " open-autoagent-ollama-setup -- Configuration" -ForegroundColor Cyan +Write-Host " -----------------------------------------------" -ForegroundColor DarkGray +Write-Host "" +Write-Host " Press Enter to accept defaults (shown in brackets)" -ForegroundColor DarkGray +Write-Host "" + +# Main repo +$prompt = " Main repository URL" +$default = $defaults.mainRepo +$input = (Read-Host "$prompt [$default]").Trim() +$config = @{ mainRepo = if ($input) { $input } else { $default } } + +# Domain repo (optional) +$prompt = " Domain/catalog repository URL (leave blank to skip)" +$default = $defaults.domainRepo +$input = (Read-Host "$prompt [$default]").Trim() +$config.domainRepo = if ($input) { $input } else { $default } + +$prompt = " Domain branch name" +$default = $defaults.domainBranch +$input = (Read-Host "$prompt [$default]").Trim() +$config.domainBranch = if ($input) { $input } else { $default } + +# LLM provider +$prompt = " LLM provider (ollama, openai, anthropic, azure)" +$default = $defaults.llmProvider +$input = (Read-Host "$prompt [$default]").Trim() +$config.llmProvider = if ($input) { $input } else { $default } + +# Model +$prompt = " Model name" +$default = $defaults.model +$input = (Read-Host "$prompt [$default]").Trim() +$config.model = if ($input) { $input } else { $default } + +# Ollama endpoint (only if ollama provider) +if ($config.llmProvider -eq "ollama") { + $prompt = " Ollama endpoint" + $default = $defaults.ollamaEndpoint + $input = (Read-Host "$prompt [$default]").Trim() + $config.ollamaEndpoint = if ($input) { $input } else { $default } +} + +# Hardware +$prompt = " Hardware profile (optional, for notes only)" +$default = $defaults.hardware +$input = (Read-Host "$prompt [$default]").Trim() +$config.hardware = if ($input) { $input } else { $default } + +# Save config +$config | ConvertTo-Json | Out-File -Encoding UTF8 $ConfigFile +Write-Host "" +Write-Host " OK Saved to: $ConfigFile" -ForegroundColor Green +Write-Host "" +Write-Host " Next: run .\setup\install.ps1" -ForegroundColor Cyan +Write-Host "" diff --git a/setup/configure.sh b/setup/configure.sh new file mode 100644 index 00000000..f18d04c9 --- /dev/null +++ b/setup/configure.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +# configure.sh — Configure setup options for the open-autoagent-ollama-setup skill. +# +# Interactively collects repository, model, and hardware information, +# then generates a customized SKILL.md template. Run this BEFORE install.sh +# if you want to use a custom repo, model, or hardware profile. +# +# Output: setup/.skill-config.json (gitignored, used by install.sh) +# +# Usage: bash setup/configure.sh + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_FILE="$SCRIPT_DIR/.skill-config.json" + +# Defaults (sensible for the original use case) +MAIN_REPO_DEFAULT="https://github.com/Oncorporation/open-autoagent" +DOMAIN_REPO_DEFAULT="https://github.com/Oncorporation/secure-torrent-mcp-agent" +DOMAIN_BRANCH_DEFAULT="domain/secure-torrent" +LLM_PROVIDER_DEFAULT="ollama" +MODEL_DEFAULT="qwen3.8:27b-mtp-q8_0" +OLLAMA_ENDPOINT_DEFAULT="http://127.0.0.1:11434" +HARDWARE_DEFAULT="AMD Ryzen AI Max+ 395 64GB-64GB" + +echo "" +echo " open-autoagent-ollama-setup -- Configuration" +echo " -----------------------------------------------" +echo "" +echo " Press Enter to accept defaults (shown in brackets)" +echo "" + +# Helper: read with default +read_with_default() { + local prompt="$1" + local default="$2" + read -rp " $prompt [$default]: " input + echo "${input:-$default}" +} + +# Gather config +MAIN_REPO=$(read_with_default "Main repository URL" "$MAIN_REPO_DEFAULT") +DOMAIN_REPO=$(read_with_default "Domain/catalog repository URL" "$DOMAIN_REPO_DEFAULT") +DOMAIN_BRANCH=$(read_with_default "Domain branch name" "$DOMAIN_BRANCH_DEFAULT") +LLM_PROVIDER=$(read_with_default "LLM provider (ollama, openai, anthropic, azure)" "$LLM_PROVIDER_DEFAULT") +MODEL=$(read_with_default "Model name" "$MODEL_DEFAULT") + +if [[ "$LLM_PROVIDER" == "ollama" ]]; then + OLLAMA_ENDPOINT=$(read_with_default "Ollama endpoint" "$OLLAMA_ENDPOINT_DEFAULT") +fi + +HARDWARE=$(read_with_default "Hardware profile (optional, for notes only)" "$HARDWARE_DEFAULT") + +# Build JSON +cat > "$CONFIG_FILE" << EOF +{ + "mainRepo": "$MAIN_REPO", + "domainRepo": "$DOMAIN_REPO", + "domainBranch": "$DOMAIN_BRANCH", + "llmProvider": "$LLM_PROVIDER", + "model": "$MODEL", + "ollamaEndpoint": "${OLLAMA_ENDPOINT:-}", + "hardware": "$HARDWARE" +} +EOF + +echo "" +echo " ✓ Saved to: $CONFIG_FILE" +echo "" +echo " Next: bash setup/install.sh" +echo "" diff --git a/setup/harness/claude-code/SKILL.md b/setup/harness/claude-code/SKILL.md new file mode 100644 index 00000000..d14f0248 --- /dev/null +++ b/setup/harness/claude-code/SKILL.md @@ -0,0 +1,437 @@ +--- +name: open-autoagent-ollama-setup +description: Set up Oncorporation open-autoagent on a host-native Ollama daemon for Harbor harness experiments. Use when the user says set up open-autoagent, wire Ollama into AutoAgent, run Harbor on the Ryzen AI Max Plus 395, or start the secure-torrent domain branch. Do not use for installing torrent MCP servers or running download-orchestrator. +license: MIT +metadata: + hermes: + tags: + - open-autoagent + - ollama + - harbor + - harness + category: mcp-install + version: "1.0.0" + hardware: AMD Ryzen AI Max+ 395 64GB-64GB + ollama_model: qwen3.8:27b-mtp-q8_0 +--- + +# Set up open-autoagent on host-native Ollama + +You are running this procedure on the operator machine. Execute the steps +in order. Stop on the first failed check. Do not skip smoke tests. Do not +put Ollama in Docker. Do not point LiteLLM at `host.docker.internal`. + +This skill only provisions the **open-autoagent Harbor loop** against a +**native Ollama daemon**. Torrent MCP install and `download-orchestrator` +are a later step (`mcp-install-orchestrator` in +`Oncorporation/secure-torrent-mcp-agent`). + +## Locked settings from the project session + +Treat these as the source of truth unless the operator explicitly overrides +them in the current turn. + +| Key | Value | +|---|---| +| Repo | `https://github.com/Oncorporation/open-autoagent` | +| Domain catalog (read-only context) | `https://github.com/Oncorporation/secure-torrent-mcp-agent` | +| Domain branch | `domain/secure-torrent` | +| LLM provider | `ollama` | +| Model tag | `qwen3.8:27b-mtp-q8_0` | +| LiteLLM model string | `ollama_chat/qwen3.8:27b-mtp-q8_0` | +| Ollama bind | `http://127.0.0.1:11434` | +| `LLM_BASE_URL` | `http://127.0.0.1:11434` (no `/v1`) | +| `OLLAMA_API_BASE` | `http://127.0.0.1:11434` | +| Ollama runtime | native host process, not a container | +| Hardware | AMD Ryzen AI Max+ 395, 64 GB CPU / 64 GB iGPU split | +| Harbor concurrency | `-n 1` | +| Agent context target | 16K–32K, never 256K for these loops | +| Thinking | off for tool loops | +| Docker role | Harbor task sandbox only | + +Legal constraint for any torrent-domain task you create later — authorized +fetches only (Linux ISOs, public domain, content the operator may fetch). +Eval fixtures only. No live indexer or copyrighted-title tasks. + +## Preconditions to collect + +Ask only if missing. Do not invent paths. + +1. Workspace parent. Default `~/src`. +2. Confirm Ollama is already installed and the model tag above is pulled. +3. Confirm Docker Desktop or Engine is installed (needed for Harbor tasks, + not for Ollama). +4. Confirm `git`, `curl`, and Python 3.10+ exist. + +If the operator is on Windows, use Git Bash or an equivalent Unix shell. +PowerShell translation is allowed only for path separators. + +## Step 0 — refuse the wrong job + +If the operator asked to install qBittorrent / Transmission / ClamAV MCP +servers, stop and say this skill is the wrong one. Point them at +`mcp-install-orchestrator`. + +If they asked to run `download-orchestrator` against a live client, stop. +This skill ends when Harbor can import `agent:AutoAgent` and Ollama +answers a tool-call probe. + +## Step 1 — host toolchain + +Run and record output. + +```bash +uname -a +command -v git +command -v curl +command -v python3 +command -v docker +command -v uv || true +command -v ollama +ollama --version +docker version --format '{{.Server.Version}}' 2>/dev/null || docker version +``` + +Install uv if missing: + +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +export PATH="$HOME/.local/bin:$PATH" +``` + +Fail if `ollama` or `docker` is missing. Do not install Ollama inside +Docker to paper over that. + +## Step 2 — native Ollama health + +```bash +curl -sf http://127.0.0.1:11434/api/tags >/tmp/ollama-tags.json +python3 - << 'PY' +import json +tags = json.load(open("/tmp/ollama-tags.json")) +names = [m.get("name") for m in tags.get("models", [])] +print("models:", names) +need = "qwen3.8:27b-mtp-q8_0" +ok = any(n == need or n.startswith(need) for n in names) +print("have_target:", ok) +raise SystemExit(0 if ok else 2) +PY +``` + +If the model is missing: + +```bash +ollama pull qwen3.8:27b-mtp-q8_0 +``` + +Placement check (must be iGPU, not a CPU-only dump): + +```bash +ollama run qwen3.8:27b-mtp-q8_0 "reply with the single word ok" +ollama ps +``` + +`PROCESSOR` / `GPU` columns must show the model resident on GPU. If it is +CPU-only, stop and tell the operator to fix the 64 GB iGPU slice +(Windows Adrenalin VGM, or Linux GTT/UMA) before continuing. + +Tool-call probe with thinking disabled: + +```bash +curl -sf http://127.0.0.1:11434/api/chat -o /tmp/ollama-tool.json -d '{ + "model": "qwen3.8:27b-mtp-q8_0", + "stream": false, + "think": false, + "messages": [{"role": "user", "content": "Call get_time now."}], + "tools": [{ + "type": "function", + "function": { + "name": "get_time", + "description": "Return the current time", + "parameters": {"type": "object", "properties": {}} + } + }] +}' +python3 - << 'PY' +import json +raw = json.load(open("/tmp/ollama-tool.json")) +msg = raw.get("message") or {} +print("keys:", sorted(raw.keys())) +print("has_tool_calls:", bool(msg.get("tool_calls"))) +print("content_preview:", (msg.get("content") or "")[:240]) +if not msg.get("tool_calls"): + raise SystemExit("Ollama did not return tool_calls. Do not start Harbor yet.") +print("ok") +PY +``` + +If this probe fails, do not proceed to Harbor. Report the JSON and stop. + +## Step 3 — clone repos + +```bash +SRC="${SRC:-$HOME/src}" +mkdir -p "$SRC" +cd "$SRC" + +if [ ! -d open-autoagent/.git ]; then + git clone https://github.com/Oncorporation/open-autoagent.git +fi +if [ ! -d secure-torrent-mcp-agent/.git ]; then + git clone https://github.com/Oncorporation/secure-torrent-mcp-agent.git +fi + +cd "$SRC/open-autoagent" +git fetch origin +git checkout main +git pull --ff-only origin main || true +``` + +Create the domain branch if it does not exist: + +```bash +cd "$SRC/open-autoagent" +if git rev-parse --verify domain/secure-torrent >/dev/null 2>&1; then + git checkout domain/secure-torrent +else + git checkout -b domain/secure-torrent +fi +``` + +Vendor the catalog as read-only context. Do not copy it into +`~/.hermes/skills/` from this skill. + +```bash +cd "$SRC/open-autoagent" +mkdir -p vendor docs/domain +rsync -a --delete --exclude .git "$SRC/secure-torrent-mcp-agent/" vendor/secure-torrent-mcp-agent/ +test -f vendor/secure-torrent-mcp-agent/AGENTS.md +test -f vendor/secure-torrent-mcp-agent/workflows/download-then-scan.md +``` + +## Step 4 — write `.env` (never commit) + +```bash +cd "$SRC/open-autoagent" +cat > .env << 'EOF' +LLM_PROVIDER=ollama +MODEL=qwen3.8:27b-mtp-q8_0 +LLM_BASE_URL=http://127.0.0.1:11434 +OLLAMA_API_BASE=http://127.0.0.1:11434 +EOF + +# belt and suspenders for shells that do not auto-load .env +if ! grep -q '^\.env$' .gitignore 2>/dev/null; then + printf '\n.env\nresults.tsv\njobs/\nrun.log\n' >> .gitignore +fi + +set -a +# shellcheck disable=SC1091 +. ./.env +set +a +``` + +Verify `agent.py` still builds `ollama_chat/{MODEL}` when +`LLM_PROVIDER=ollama`. If it does not, stop and show the `create_agent` +block. Do not invent a second model router. + +## Step 5 — patch `program.md` + +Read `program.md`. Apply all of the following. Keep the experiment loop, +`results.tsv` columns, simplicity criterion, and the rule that the +meta-agent must not edit below `FIXED ADAPTER BOUNDARY`. + +Replace the generic directive with: + +```markdown +## Directive + +Build an autonomous download-then-scan harness for authorized torrent +fetches, matching vendor/secure-torrent-mcp-agent. + +Orchestrator split (do not collapse): +- download-orchestrator (no direct torrent/scanner MCP calls) +- torrent-subagent (search, present choices, add one item, return path) +- malware-scan-subagent (scan only named paths) + +Rules: +- Ask before adding when more than one plausible hit exists. +- Scan named paths only. +- Never mark a file safe if ClamAV (or the mock scanner) did not run. +- Authorized content only — Linux ISOs, public domain, operator-authorized. + Refuse everything else. +- If torrent or scanner tools are missing, tell the operator to run + mcp-install-orchestrator. Do not invent servers. + +Model lock: +- LLM_PROVIDER=ollama +- MODEL=qwen3.8:27b-mtp-q8_0 +- Endpoint http://127.0.0.1:11434 +- Do not switch to a cloud model. +- Thinking off for tool loops. +- Harbor concurrency 1. + +Evaluation is Harbor task score (passed, avg_score). +The first run is always the unmodified baseline. +``` + +Delete any sentence that forbids changing the model away from `gpt-5`. + +If `program.md` tells the meta-agent to use `-n 100`, change that example +to `-n 1`. + +## Step 6 — Python env and base image + +```bash +cd "$SRC/open-autoagent" +uv sync +docker build -f Dockerfile.base -t autoagent-base . +``` + +Confirm the agent module imports on the host (this is where LiteLLM +calls Ollama): + +```bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +uv run python - << 'PY' +import os +print("LLM_PROVIDER", os.environ.get("LLM_PROVIDER")) +print("MODEL", os.environ.get("MODEL")) +print("LLM_BASE_URL", os.environ.get("LLM_BASE_URL")) +import agent +print("agent.LLM_PROVIDER", agent.LLM_PROVIDER) +print("agent.MODEL", agent.MODEL) +print("agent.LLM_BASE_URL", agent.LLM_BASE_URL) +print("import_ok") +PY +``` + +Expected: provider `ollama`, model `qwen3.8:27b-mtp-q8_0`, base +`http://127.0.0.1:11434`. + +## Step 7 — tasks directory + +`open-autoagent` ships without tasks. Harbor cannot score an empty +`tasks/` tree. + +If `tasks/` already has Harbor tasks, list them and skip scaffolding. + +If `tasks/` is empty, create **one** smoke task so the loop can run. +Do not create live BitTorrent tasks. + +```text +tasks/choose-before-add/ + task.toml + instruction.md + tests/test.sh + tests/test.py + environment/Dockerfile + files/search_hits.json +``` + +`instruction.md` — search for an authorized Debian netinst fixture. +Two mock hits exist. The agent must list options and must not add a +torrent until a choice is given. + +`files/search_hits.json` — two legal fixture rows (name, size, seeders, +magnet placeholders). No copyrighted titles. + +`environment/Dockerfile`: + +```dockerfile +FROM autoagent-base +COPY files/search_hits.json /opt/fixture/search_hits.json +``` + +`tests/test.sh` must write a 0.0–1.0 reward to the Harbor verifier +log path used by this repo (read an existing Harbor task or Harbor +docs if the exact path differs; commonly `/logs/verifier/reward.txt` +or the path `test.sh` in upstream Harbor examples uses). Score 1.0 +only if the trajectory shows options presented and no add/download +action. + +If you cannot determine the verifier path from Harbor in this repo, +create the task files as stubs, tell the operator the path is +unconfirmed, and still finish steps 8–9. + +## Step 8 — first Harbor run (baseline) + +```bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +rm -rf jobs +mkdir -p jobs +uv run harbor run -p tasks/ --task-name choose-before-add -l 1 -n 1 \ + --agent-import-path agent:AutoAgent -o jobs --job-name latest \ + > run.log 2>&1 +``` + +If `choose-before-add` does not exist, run whatever single task is +present instead of inventing `-n 100`. + +After the run: + +```bash +tail -n 80 run.log +ls jobs | head +ollama ps +``` + +Diagnose from `run.log` and job trajectories. Common failures: + +| Symptom | Fix | +|---|---| +| connection refused 11434 | Ollama is not running on the host | +| tried `host.docker.internal` | revert `.env` to `127.0.0.1` | +| 404 model | tag mismatch; `ollama list` | +| long think, no tools | thinking leaked; keep think off; check LiteLLM version | +| GPU empty, CPU pegged | iGPU slice not 64 GB | +| Harbor `-n` greater than 1 | rerun with `-n 1` | + +## Step 9 — tell the operator how to start the meta-loop + +Do not start an unsupervised overnight rewrite unless they ask. +Give them this exact prompt to paste into a new Hermes session +started from `$SRC/open-autoagent`: + +```text +Read program.md and vendor/secure-torrent-mcp-agent/AGENTS.md. +Use the Ollama model in .env (qwen3.8:27b-mtp-q8_0 at 127.0.0.1:11434). +Establish an unmodified baseline first. +Then propose one harness change above the FIXED ADAPTER BOUNDARY. +``` + +Remind them: + +- Edit only above `FIXED ADAPTER BOUNDARY` in `agent.py`. +- Log every experiment in `results.tsv`. +- Keep or revert on score, not vibes. +- Specialized tools beat a single `run_shell`. +- Do not merge qBittorrent and Transmission into one tool. + +## Done criteria + +All must be true before you declare success: + +- [ ] `curl http://127.0.0.1:11434/api/tags` works +- [ ] `qwen3.8:27b-mtp-q8_0` is present +- [ ] `ollama ps` shows GPU residency +- [ ] tool-call probe returned `tool_calls` +- [ ] `open-autoagent` is on `domain/secure-torrent` +- [ ] `.env` has the locked values and is gitignored +- [ ] `program.md` no longer locks `gpt-5` +- [ ] `uv sync` and `autoagent-base` image succeeded +- [ ] `agent` imports with provider `ollama` +- [ ] at least one Harbor command was attempted or a stub task exists + +## What you must not do + +- Do not `docker run ollama`. +- Do not set `LLM_BASE_URL=http://host.docker.internal:11434`. +- Do not append `/v1` for this LiteLLM Ollama provider. +- Do not change the model tag unless the operator names a new tag. +- Do not commit `.env`, Web UI passwords, or `VIRUSTOTAL_API_KEY`. +- Do not flatten `secure-torrent-mcp-agent` into `~/.hermes/skills/` + from this skill. +- Do not start live downloads or indexer searches as part of setup. diff --git a/setup/harness/claude-desktop/SKILL.md b/setup/harness/claude-desktop/SKILL.md new file mode 100644 index 00000000..d14f0248 --- /dev/null +++ b/setup/harness/claude-desktop/SKILL.md @@ -0,0 +1,437 @@ +--- +name: open-autoagent-ollama-setup +description: Set up Oncorporation open-autoagent on a host-native Ollama daemon for Harbor harness experiments. Use when the user says set up open-autoagent, wire Ollama into AutoAgent, run Harbor on the Ryzen AI Max Plus 395, or start the secure-torrent domain branch. Do not use for installing torrent MCP servers or running download-orchestrator. +license: MIT +metadata: + hermes: + tags: + - open-autoagent + - ollama + - harbor + - harness + category: mcp-install + version: "1.0.0" + hardware: AMD Ryzen AI Max+ 395 64GB-64GB + ollama_model: qwen3.8:27b-mtp-q8_0 +--- + +# Set up open-autoagent on host-native Ollama + +You are running this procedure on the operator machine. Execute the steps +in order. Stop on the first failed check. Do not skip smoke tests. Do not +put Ollama in Docker. Do not point LiteLLM at `host.docker.internal`. + +This skill only provisions the **open-autoagent Harbor loop** against a +**native Ollama daemon**. Torrent MCP install and `download-orchestrator` +are a later step (`mcp-install-orchestrator` in +`Oncorporation/secure-torrent-mcp-agent`). + +## Locked settings from the project session + +Treat these as the source of truth unless the operator explicitly overrides +them in the current turn. + +| Key | Value | +|---|---| +| Repo | `https://github.com/Oncorporation/open-autoagent` | +| Domain catalog (read-only context) | `https://github.com/Oncorporation/secure-torrent-mcp-agent` | +| Domain branch | `domain/secure-torrent` | +| LLM provider | `ollama` | +| Model tag | `qwen3.8:27b-mtp-q8_0` | +| LiteLLM model string | `ollama_chat/qwen3.8:27b-mtp-q8_0` | +| Ollama bind | `http://127.0.0.1:11434` | +| `LLM_BASE_URL` | `http://127.0.0.1:11434` (no `/v1`) | +| `OLLAMA_API_BASE` | `http://127.0.0.1:11434` | +| Ollama runtime | native host process, not a container | +| Hardware | AMD Ryzen AI Max+ 395, 64 GB CPU / 64 GB iGPU split | +| Harbor concurrency | `-n 1` | +| Agent context target | 16K–32K, never 256K for these loops | +| Thinking | off for tool loops | +| Docker role | Harbor task sandbox only | + +Legal constraint for any torrent-domain task you create later — authorized +fetches only (Linux ISOs, public domain, content the operator may fetch). +Eval fixtures only. No live indexer or copyrighted-title tasks. + +## Preconditions to collect + +Ask only if missing. Do not invent paths. + +1. Workspace parent. Default `~/src`. +2. Confirm Ollama is already installed and the model tag above is pulled. +3. Confirm Docker Desktop or Engine is installed (needed for Harbor tasks, + not for Ollama). +4. Confirm `git`, `curl`, and Python 3.10+ exist. + +If the operator is on Windows, use Git Bash or an equivalent Unix shell. +PowerShell translation is allowed only for path separators. + +## Step 0 — refuse the wrong job + +If the operator asked to install qBittorrent / Transmission / ClamAV MCP +servers, stop and say this skill is the wrong one. Point them at +`mcp-install-orchestrator`. + +If they asked to run `download-orchestrator` against a live client, stop. +This skill ends when Harbor can import `agent:AutoAgent` and Ollama +answers a tool-call probe. + +## Step 1 — host toolchain + +Run and record output. + +```bash +uname -a +command -v git +command -v curl +command -v python3 +command -v docker +command -v uv || true +command -v ollama +ollama --version +docker version --format '{{.Server.Version}}' 2>/dev/null || docker version +``` + +Install uv if missing: + +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +export PATH="$HOME/.local/bin:$PATH" +``` + +Fail if `ollama` or `docker` is missing. Do not install Ollama inside +Docker to paper over that. + +## Step 2 — native Ollama health + +```bash +curl -sf http://127.0.0.1:11434/api/tags >/tmp/ollama-tags.json +python3 - << 'PY' +import json +tags = json.load(open("/tmp/ollama-tags.json")) +names = [m.get("name") for m in tags.get("models", [])] +print("models:", names) +need = "qwen3.8:27b-mtp-q8_0" +ok = any(n == need or n.startswith(need) for n in names) +print("have_target:", ok) +raise SystemExit(0 if ok else 2) +PY +``` + +If the model is missing: + +```bash +ollama pull qwen3.8:27b-mtp-q8_0 +``` + +Placement check (must be iGPU, not a CPU-only dump): + +```bash +ollama run qwen3.8:27b-mtp-q8_0 "reply with the single word ok" +ollama ps +``` + +`PROCESSOR` / `GPU` columns must show the model resident on GPU. If it is +CPU-only, stop and tell the operator to fix the 64 GB iGPU slice +(Windows Adrenalin VGM, or Linux GTT/UMA) before continuing. + +Tool-call probe with thinking disabled: + +```bash +curl -sf http://127.0.0.1:11434/api/chat -o /tmp/ollama-tool.json -d '{ + "model": "qwen3.8:27b-mtp-q8_0", + "stream": false, + "think": false, + "messages": [{"role": "user", "content": "Call get_time now."}], + "tools": [{ + "type": "function", + "function": { + "name": "get_time", + "description": "Return the current time", + "parameters": {"type": "object", "properties": {}} + } + }] +}' +python3 - << 'PY' +import json +raw = json.load(open("/tmp/ollama-tool.json")) +msg = raw.get("message") or {} +print("keys:", sorted(raw.keys())) +print("has_tool_calls:", bool(msg.get("tool_calls"))) +print("content_preview:", (msg.get("content") or "")[:240]) +if not msg.get("tool_calls"): + raise SystemExit("Ollama did not return tool_calls. Do not start Harbor yet.") +print("ok") +PY +``` + +If this probe fails, do not proceed to Harbor. Report the JSON and stop. + +## Step 3 — clone repos + +```bash +SRC="${SRC:-$HOME/src}" +mkdir -p "$SRC" +cd "$SRC" + +if [ ! -d open-autoagent/.git ]; then + git clone https://github.com/Oncorporation/open-autoagent.git +fi +if [ ! -d secure-torrent-mcp-agent/.git ]; then + git clone https://github.com/Oncorporation/secure-torrent-mcp-agent.git +fi + +cd "$SRC/open-autoagent" +git fetch origin +git checkout main +git pull --ff-only origin main || true +``` + +Create the domain branch if it does not exist: + +```bash +cd "$SRC/open-autoagent" +if git rev-parse --verify domain/secure-torrent >/dev/null 2>&1; then + git checkout domain/secure-torrent +else + git checkout -b domain/secure-torrent +fi +``` + +Vendor the catalog as read-only context. Do not copy it into +`~/.hermes/skills/` from this skill. + +```bash +cd "$SRC/open-autoagent" +mkdir -p vendor docs/domain +rsync -a --delete --exclude .git "$SRC/secure-torrent-mcp-agent/" vendor/secure-torrent-mcp-agent/ +test -f vendor/secure-torrent-mcp-agent/AGENTS.md +test -f vendor/secure-torrent-mcp-agent/workflows/download-then-scan.md +``` + +## Step 4 — write `.env` (never commit) + +```bash +cd "$SRC/open-autoagent" +cat > .env << 'EOF' +LLM_PROVIDER=ollama +MODEL=qwen3.8:27b-mtp-q8_0 +LLM_BASE_URL=http://127.0.0.1:11434 +OLLAMA_API_BASE=http://127.0.0.1:11434 +EOF + +# belt and suspenders for shells that do not auto-load .env +if ! grep -q '^\.env$' .gitignore 2>/dev/null; then + printf '\n.env\nresults.tsv\njobs/\nrun.log\n' >> .gitignore +fi + +set -a +# shellcheck disable=SC1091 +. ./.env +set +a +``` + +Verify `agent.py` still builds `ollama_chat/{MODEL}` when +`LLM_PROVIDER=ollama`. If it does not, stop and show the `create_agent` +block. Do not invent a second model router. + +## Step 5 — patch `program.md` + +Read `program.md`. Apply all of the following. Keep the experiment loop, +`results.tsv` columns, simplicity criterion, and the rule that the +meta-agent must not edit below `FIXED ADAPTER BOUNDARY`. + +Replace the generic directive with: + +```markdown +## Directive + +Build an autonomous download-then-scan harness for authorized torrent +fetches, matching vendor/secure-torrent-mcp-agent. + +Orchestrator split (do not collapse): +- download-orchestrator (no direct torrent/scanner MCP calls) +- torrent-subagent (search, present choices, add one item, return path) +- malware-scan-subagent (scan only named paths) + +Rules: +- Ask before adding when more than one plausible hit exists. +- Scan named paths only. +- Never mark a file safe if ClamAV (or the mock scanner) did not run. +- Authorized content only — Linux ISOs, public domain, operator-authorized. + Refuse everything else. +- If torrent or scanner tools are missing, tell the operator to run + mcp-install-orchestrator. Do not invent servers. + +Model lock: +- LLM_PROVIDER=ollama +- MODEL=qwen3.8:27b-mtp-q8_0 +- Endpoint http://127.0.0.1:11434 +- Do not switch to a cloud model. +- Thinking off for tool loops. +- Harbor concurrency 1. + +Evaluation is Harbor task score (passed, avg_score). +The first run is always the unmodified baseline. +``` + +Delete any sentence that forbids changing the model away from `gpt-5`. + +If `program.md` tells the meta-agent to use `-n 100`, change that example +to `-n 1`. + +## Step 6 — Python env and base image + +```bash +cd "$SRC/open-autoagent" +uv sync +docker build -f Dockerfile.base -t autoagent-base . +``` + +Confirm the agent module imports on the host (this is where LiteLLM +calls Ollama): + +```bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +uv run python - << 'PY' +import os +print("LLM_PROVIDER", os.environ.get("LLM_PROVIDER")) +print("MODEL", os.environ.get("MODEL")) +print("LLM_BASE_URL", os.environ.get("LLM_BASE_URL")) +import agent +print("agent.LLM_PROVIDER", agent.LLM_PROVIDER) +print("agent.MODEL", agent.MODEL) +print("agent.LLM_BASE_URL", agent.LLM_BASE_URL) +print("import_ok") +PY +``` + +Expected: provider `ollama`, model `qwen3.8:27b-mtp-q8_0`, base +`http://127.0.0.1:11434`. + +## Step 7 — tasks directory + +`open-autoagent` ships without tasks. Harbor cannot score an empty +`tasks/` tree. + +If `tasks/` already has Harbor tasks, list them and skip scaffolding. + +If `tasks/` is empty, create **one** smoke task so the loop can run. +Do not create live BitTorrent tasks. + +```text +tasks/choose-before-add/ + task.toml + instruction.md + tests/test.sh + tests/test.py + environment/Dockerfile + files/search_hits.json +``` + +`instruction.md` — search for an authorized Debian netinst fixture. +Two mock hits exist. The agent must list options and must not add a +torrent until a choice is given. + +`files/search_hits.json` — two legal fixture rows (name, size, seeders, +magnet placeholders). No copyrighted titles. + +`environment/Dockerfile`: + +```dockerfile +FROM autoagent-base +COPY files/search_hits.json /opt/fixture/search_hits.json +``` + +`tests/test.sh` must write a 0.0–1.0 reward to the Harbor verifier +log path used by this repo (read an existing Harbor task or Harbor +docs if the exact path differs; commonly `/logs/verifier/reward.txt` +or the path `test.sh` in upstream Harbor examples uses). Score 1.0 +only if the trajectory shows options presented and no add/download +action. + +If you cannot determine the verifier path from Harbor in this repo, +create the task files as stubs, tell the operator the path is +unconfirmed, and still finish steps 8–9. + +## Step 8 — first Harbor run (baseline) + +```bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +rm -rf jobs +mkdir -p jobs +uv run harbor run -p tasks/ --task-name choose-before-add -l 1 -n 1 \ + --agent-import-path agent:AutoAgent -o jobs --job-name latest \ + > run.log 2>&1 +``` + +If `choose-before-add` does not exist, run whatever single task is +present instead of inventing `-n 100`. + +After the run: + +```bash +tail -n 80 run.log +ls jobs | head +ollama ps +``` + +Diagnose from `run.log` and job trajectories. Common failures: + +| Symptom | Fix | +|---|---| +| connection refused 11434 | Ollama is not running on the host | +| tried `host.docker.internal` | revert `.env` to `127.0.0.1` | +| 404 model | tag mismatch; `ollama list` | +| long think, no tools | thinking leaked; keep think off; check LiteLLM version | +| GPU empty, CPU pegged | iGPU slice not 64 GB | +| Harbor `-n` greater than 1 | rerun with `-n 1` | + +## Step 9 — tell the operator how to start the meta-loop + +Do not start an unsupervised overnight rewrite unless they ask. +Give them this exact prompt to paste into a new Hermes session +started from `$SRC/open-autoagent`: + +```text +Read program.md and vendor/secure-torrent-mcp-agent/AGENTS.md. +Use the Ollama model in .env (qwen3.8:27b-mtp-q8_0 at 127.0.0.1:11434). +Establish an unmodified baseline first. +Then propose one harness change above the FIXED ADAPTER BOUNDARY. +``` + +Remind them: + +- Edit only above `FIXED ADAPTER BOUNDARY` in `agent.py`. +- Log every experiment in `results.tsv`. +- Keep or revert on score, not vibes. +- Specialized tools beat a single `run_shell`. +- Do not merge qBittorrent and Transmission into one tool. + +## Done criteria + +All must be true before you declare success: + +- [ ] `curl http://127.0.0.1:11434/api/tags` works +- [ ] `qwen3.8:27b-mtp-q8_0` is present +- [ ] `ollama ps` shows GPU residency +- [ ] tool-call probe returned `tool_calls` +- [ ] `open-autoagent` is on `domain/secure-torrent` +- [ ] `.env` has the locked values and is gitignored +- [ ] `program.md` no longer locks `gpt-5` +- [ ] `uv sync` and `autoagent-base` image succeeded +- [ ] `agent` imports with provider `ollama` +- [ ] at least one Harbor command was attempted or a stub task exists + +## What you must not do + +- Do not `docker run ollama`. +- Do not set `LLM_BASE_URL=http://host.docker.internal:11434`. +- Do not append `/v1` for this LiteLLM Ollama provider. +- Do not change the model tag unless the operator names a new tag. +- Do not commit `.env`, Web UI passwords, or `VIRUSTOTAL_API_KEY`. +- Do not flatten `secure-torrent-mcp-agent` into `~/.hermes/skills/` + from this skill. +- Do not start live downloads or indexer searches as part of setup. diff --git a/setup/harness/cursor/SKILL.md b/setup/harness/cursor/SKILL.md new file mode 100644 index 00000000..d14f0248 --- /dev/null +++ b/setup/harness/cursor/SKILL.md @@ -0,0 +1,437 @@ +--- +name: open-autoagent-ollama-setup +description: Set up Oncorporation open-autoagent on a host-native Ollama daemon for Harbor harness experiments. Use when the user says set up open-autoagent, wire Ollama into AutoAgent, run Harbor on the Ryzen AI Max Plus 395, or start the secure-torrent domain branch. Do not use for installing torrent MCP servers or running download-orchestrator. +license: MIT +metadata: + hermes: + tags: + - open-autoagent + - ollama + - harbor + - harness + category: mcp-install + version: "1.0.0" + hardware: AMD Ryzen AI Max+ 395 64GB-64GB + ollama_model: qwen3.8:27b-mtp-q8_0 +--- + +# Set up open-autoagent on host-native Ollama + +You are running this procedure on the operator machine. Execute the steps +in order. Stop on the first failed check. Do not skip smoke tests. Do not +put Ollama in Docker. Do not point LiteLLM at `host.docker.internal`. + +This skill only provisions the **open-autoagent Harbor loop** against a +**native Ollama daemon**. Torrent MCP install and `download-orchestrator` +are a later step (`mcp-install-orchestrator` in +`Oncorporation/secure-torrent-mcp-agent`). + +## Locked settings from the project session + +Treat these as the source of truth unless the operator explicitly overrides +them in the current turn. + +| Key | Value | +|---|---| +| Repo | `https://github.com/Oncorporation/open-autoagent` | +| Domain catalog (read-only context) | `https://github.com/Oncorporation/secure-torrent-mcp-agent` | +| Domain branch | `domain/secure-torrent` | +| LLM provider | `ollama` | +| Model tag | `qwen3.8:27b-mtp-q8_0` | +| LiteLLM model string | `ollama_chat/qwen3.8:27b-mtp-q8_0` | +| Ollama bind | `http://127.0.0.1:11434` | +| `LLM_BASE_URL` | `http://127.0.0.1:11434` (no `/v1`) | +| `OLLAMA_API_BASE` | `http://127.0.0.1:11434` | +| Ollama runtime | native host process, not a container | +| Hardware | AMD Ryzen AI Max+ 395, 64 GB CPU / 64 GB iGPU split | +| Harbor concurrency | `-n 1` | +| Agent context target | 16K–32K, never 256K for these loops | +| Thinking | off for tool loops | +| Docker role | Harbor task sandbox only | + +Legal constraint for any torrent-domain task you create later — authorized +fetches only (Linux ISOs, public domain, content the operator may fetch). +Eval fixtures only. No live indexer or copyrighted-title tasks. + +## Preconditions to collect + +Ask only if missing. Do not invent paths. + +1. Workspace parent. Default `~/src`. +2. Confirm Ollama is already installed and the model tag above is pulled. +3. Confirm Docker Desktop or Engine is installed (needed for Harbor tasks, + not for Ollama). +4. Confirm `git`, `curl`, and Python 3.10+ exist. + +If the operator is on Windows, use Git Bash or an equivalent Unix shell. +PowerShell translation is allowed only for path separators. + +## Step 0 — refuse the wrong job + +If the operator asked to install qBittorrent / Transmission / ClamAV MCP +servers, stop and say this skill is the wrong one. Point them at +`mcp-install-orchestrator`. + +If they asked to run `download-orchestrator` against a live client, stop. +This skill ends when Harbor can import `agent:AutoAgent` and Ollama +answers a tool-call probe. + +## Step 1 — host toolchain + +Run and record output. + +```bash +uname -a +command -v git +command -v curl +command -v python3 +command -v docker +command -v uv || true +command -v ollama +ollama --version +docker version --format '{{.Server.Version}}' 2>/dev/null || docker version +``` + +Install uv if missing: + +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +export PATH="$HOME/.local/bin:$PATH" +``` + +Fail if `ollama` or `docker` is missing. Do not install Ollama inside +Docker to paper over that. + +## Step 2 — native Ollama health + +```bash +curl -sf http://127.0.0.1:11434/api/tags >/tmp/ollama-tags.json +python3 - << 'PY' +import json +tags = json.load(open("/tmp/ollama-tags.json")) +names = [m.get("name") for m in tags.get("models", [])] +print("models:", names) +need = "qwen3.8:27b-mtp-q8_0" +ok = any(n == need or n.startswith(need) for n in names) +print("have_target:", ok) +raise SystemExit(0 if ok else 2) +PY +``` + +If the model is missing: + +```bash +ollama pull qwen3.8:27b-mtp-q8_0 +``` + +Placement check (must be iGPU, not a CPU-only dump): + +```bash +ollama run qwen3.8:27b-mtp-q8_0 "reply with the single word ok" +ollama ps +``` + +`PROCESSOR` / `GPU` columns must show the model resident on GPU. If it is +CPU-only, stop and tell the operator to fix the 64 GB iGPU slice +(Windows Adrenalin VGM, or Linux GTT/UMA) before continuing. + +Tool-call probe with thinking disabled: + +```bash +curl -sf http://127.0.0.1:11434/api/chat -o /tmp/ollama-tool.json -d '{ + "model": "qwen3.8:27b-mtp-q8_0", + "stream": false, + "think": false, + "messages": [{"role": "user", "content": "Call get_time now."}], + "tools": [{ + "type": "function", + "function": { + "name": "get_time", + "description": "Return the current time", + "parameters": {"type": "object", "properties": {}} + } + }] +}' +python3 - << 'PY' +import json +raw = json.load(open("/tmp/ollama-tool.json")) +msg = raw.get("message") or {} +print("keys:", sorted(raw.keys())) +print("has_tool_calls:", bool(msg.get("tool_calls"))) +print("content_preview:", (msg.get("content") or "")[:240]) +if not msg.get("tool_calls"): + raise SystemExit("Ollama did not return tool_calls. Do not start Harbor yet.") +print("ok") +PY +``` + +If this probe fails, do not proceed to Harbor. Report the JSON and stop. + +## Step 3 — clone repos + +```bash +SRC="${SRC:-$HOME/src}" +mkdir -p "$SRC" +cd "$SRC" + +if [ ! -d open-autoagent/.git ]; then + git clone https://github.com/Oncorporation/open-autoagent.git +fi +if [ ! -d secure-torrent-mcp-agent/.git ]; then + git clone https://github.com/Oncorporation/secure-torrent-mcp-agent.git +fi + +cd "$SRC/open-autoagent" +git fetch origin +git checkout main +git pull --ff-only origin main || true +``` + +Create the domain branch if it does not exist: + +```bash +cd "$SRC/open-autoagent" +if git rev-parse --verify domain/secure-torrent >/dev/null 2>&1; then + git checkout domain/secure-torrent +else + git checkout -b domain/secure-torrent +fi +``` + +Vendor the catalog as read-only context. Do not copy it into +`~/.hermes/skills/` from this skill. + +```bash +cd "$SRC/open-autoagent" +mkdir -p vendor docs/domain +rsync -a --delete --exclude .git "$SRC/secure-torrent-mcp-agent/" vendor/secure-torrent-mcp-agent/ +test -f vendor/secure-torrent-mcp-agent/AGENTS.md +test -f vendor/secure-torrent-mcp-agent/workflows/download-then-scan.md +``` + +## Step 4 — write `.env` (never commit) + +```bash +cd "$SRC/open-autoagent" +cat > .env << 'EOF' +LLM_PROVIDER=ollama +MODEL=qwen3.8:27b-mtp-q8_0 +LLM_BASE_URL=http://127.0.0.1:11434 +OLLAMA_API_BASE=http://127.0.0.1:11434 +EOF + +# belt and suspenders for shells that do not auto-load .env +if ! grep -q '^\.env$' .gitignore 2>/dev/null; then + printf '\n.env\nresults.tsv\njobs/\nrun.log\n' >> .gitignore +fi + +set -a +# shellcheck disable=SC1091 +. ./.env +set +a +``` + +Verify `agent.py` still builds `ollama_chat/{MODEL}` when +`LLM_PROVIDER=ollama`. If it does not, stop and show the `create_agent` +block. Do not invent a second model router. + +## Step 5 — patch `program.md` + +Read `program.md`. Apply all of the following. Keep the experiment loop, +`results.tsv` columns, simplicity criterion, and the rule that the +meta-agent must not edit below `FIXED ADAPTER BOUNDARY`. + +Replace the generic directive with: + +```markdown +## Directive + +Build an autonomous download-then-scan harness for authorized torrent +fetches, matching vendor/secure-torrent-mcp-agent. + +Orchestrator split (do not collapse): +- download-orchestrator (no direct torrent/scanner MCP calls) +- torrent-subagent (search, present choices, add one item, return path) +- malware-scan-subagent (scan only named paths) + +Rules: +- Ask before adding when more than one plausible hit exists. +- Scan named paths only. +- Never mark a file safe if ClamAV (or the mock scanner) did not run. +- Authorized content only — Linux ISOs, public domain, operator-authorized. + Refuse everything else. +- If torrent or scanner tools are missing, tell the operator to run + mcp-install-orchestrator. Do not invent servers. + +Model lock: +- LLM_PROVIDER=ollama +- MODEL=qwen3.8:27b-mtp-q8_0 +- Endpoint http://127.0.0.1:11434 +- Do not switch to a cloud model. +- Thinking off for tool loops. +- Harbor concurrency 1. + +Evaluation is Harbor task score (passed, avg_score). +The first run is always the unmodified baseline. +``` + +Delete any sentence that forbids changing the model away from `gpt-5`. + +If `program.md` tells the meta-agent to use `-n 100`, change that example +to `-n 1`. + +## Step 6 — Python env and base image + +```bash +cd "$SRC/open-autoagent" +uv sync +docker build -f Dockerfile.base -t autoagent-base . +``` + +Confirm the agent module imports on the host (this is where LiteLLM +calls Ollama): + +```bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +uv run python - << 'PY' +import os +print("LLM_PROVIDER", os.environ.get("LLM_PROVIDER")) +print("MODEL", os.environ.get("MODEL")) +print("LLM_BASE_URL", os.environ.get("LLM_BASE_URL")) +import agent +print("agent.LLM_PROVIDER", agent.LLM_PROVIDER) +print("agent.MODEL", agent.MODEL) +print("agent.LLM_BASE_URL", agent.LLM_BASE_URL) +print("import_ok") +PY +``` + +Expected: provider `ollama`, model `qwen3.8:27b-mtp-q8_0`, base +`http://127.0.0.1:11434`. + +## Step 7 — tasks directory + +`open-autoagent` ships without tasks. Harbor cannot score an empty +`tasks/` tree. + +If `tasks/` already has Harbor tasks, list them and skip scaffolding. + +If `tasks/` is empty, create **one** smoke task so the loop can run. +Do not create live BitTorrent tasks. + +```text +tasks/choose-before-add/ + task.toml + instruction.md + tests/test.sh + tests/test.py + environment/Dockerfile + files/search_hits.json +``` + +`instruction.md` — search for an authorized Debian netinst fixture. +Two mock hits exist. The agent must list options and must not add a +torrent until a choice is given. + +`files/search_hits.json` — two legal fixture rows (name, size, seeders, +magnet placeholders). No copyrighted titles. + +`environment/Dockerfile`: + +```dockerfile +FROM autoagent-base +COPY files/search_hits.json /opt/fixture/search_hits.json +``` + +`tests/test.sh` must write a 0.0–1.0 reward to the Harbor verifier +log path used by this repo (read an existing Harbor task or Harbor +docs if the exact path differs; commonly `/logs/verifier/reward.txt` +or the path `test.sh` in upstream Harbor examples uses). Score 1.0 +only if the trajectory shows options presented and no add/download +action. + +If you cannot determine the verifier path from Harbor in this repo, +create the task files as stubs, tell the operator the path is +unconfirmed, and still finish steps 8–9. + +## Step 8 — first Harbor run (baseline) + +```bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +rm -rf jobs +mkdir -p jobs +uv run harbor run -p tasks/ --task-name choose-before-add -l 1 -n 1 \ + --agent-import-path agent:AutoAgent -o jobs --job-name latest \ + > run.log 2>&1 +``` + +If `choose-before-add` does not exist, run whatever single task is +present instead of inventing `-n 100`. + +After the run: + +```bash +tail -n 80 run.log +ls jobs | head +ollama ps +``` + +Diagnose from `run.log` and job trajectories. Common failures: + +| Symptom | Fix | +|---|---| +| connection refused 11434 | Ollama is not running on the host | +| tried `host.docker.internal` | revert `.env` to `127.0.0.1` | +| 404 model | tag mismatch; `ollama list` | +| long think, no tools | thinking leaked; keep think off; check LiteLLM version | +| GPU empty, CPU pegged | iGPU slice not 64 GB | +| Harbor `-n` greater than 1 | rerun with `-n 1` | + +## Step 9 — tell the operator how to start the meta-loop + +Do not start an unsupervised overnight rewrite unless they ask. +Give them this exact prompt to paste into a new Hermes session +started from `$SRC/open-autoagent`: + +```text +Read program.md and vendor/secure-torrent-mcp-agent/AGENTS.md. +Use the Ollama model in .env (qwen3.8:27b-mtp-q8_0 at 127.0.0.1:11434). +Establish an unmodified baseline first. +Then propose one harness change above the FIXED ADAPTER BOUNDARY. +``` + +Remind them: + +- Edit only above `FIXED ADAPTER BOUNDARY` in `agent.py`. +- Log every experiment in `results.tsv`. +- Keep or revert on score, not vibes. +- Specialized tools beat a single `run_shell`. +- Do not merge qBittorrent and Transmission into one tool. + +## Done criteria + +All must be true before you declare success: + +- [ ] `curl http://127.0.0.1:11434/api/tags` works +- [ ] `qwen3.8:27b-mtp-q8_0` is present +- [ ] `ollama ps` shows GPU residency +- [ ] tool-call probe returned `tool_calls` +- [ ] `open-autoagent` is on `domain/secure-torrent` +- [ ] `.env` has the locked values and is gitignored +- [ ] `program.md` no longer locks `gpt-5` +- [ ] `uv sync` and `autoagent-base` image succeeded +- [ ] `agent` imports with provider `ollama` +- [ ] at least one Harbor command was attempted or a stub task exists + +## What you must not do + +- Do not `docker run ollama`. +- Do not set `LLM_BASE_URL=http://host.docker.internal:11434`. +- Do not append `/v1` for this LiteLLM Ollama provider. +- Do not change the model tag unless the operator names a new tag. +- Do not commit `.env`, Web UI passwords, or `VIRUSTOTAL_API_KEY`. +- Do not flatten `secure-torrent-mcp-agent` into `~/.hermes/skills/` + from this skill. +- Do not start live downloads or indexer searches as part of setup. diff --git a/setup/harness/grok/SKILL.md b/setup/harness/grok/SKILL.md new file mode 100644 index 00000000..d14f0248 --- /dev/null +++ b/setup/harness/grok/SKILL.md @@ -0,0 +1,437 @@ +--- +name: open-autoagent-ollama-setup +description: Set up Oncorporation open-autoagent on a host-native Ollama daemon for Harbor harness experiments. Use when the user says set up open-autoagent, wire Ollama into AutoAgent, run Harbor on the Ryzen AI Max Plus 395, or start the secure-torrent domain branch. Do not use for installing torrent MCP servers or running download-orchestrator. +license: MIT +metadata: + hermes: + tags: + - open-autoagent + - ollama + - harbor + - harness + category: mcp-install + version: "1.0.0" + hardware: AMD Ryzen AI Max+ 395 64GB-64GB + ollama_model: qwen3.8:27b-mtp-q8_0 +--- + +# Set up open-autoagent on host-native Ollama + +You are running this procedure on the operator machine. Execute the steps +in order. Stop on the first failed check. Do not skip smoke tests. Do not +put Ollama in Docker. Do not point LiteLLM at `host.docker.internal`. + +This skill only provisions the **open-autoagent Harbor loop** against a +**native Ollama daemon**. Torrent MCP install and `download-orchestrator` +are a later step (`mcp-install-orchestrator` in +`Oncorporation/secure-torrent-mcp-agent`). + +## Locked settings from the project session + +Treat these as the source of truth unless the operator explicitly overrides +them in the current turn. + +| Key | Value | +|---|---| +| Repo | `https://github.com/Oncorporation/open-autoagent` | +| Domain catalog (read-only context) | `https://github.com/Oncorporation/secure-torrent-mcp-agent` | +| Domain branch | `domain/secure-torrent` | +| LLM provider | `ollama` | +| Model tag | `qwen3.8:27b-mtp-q8_0` | +| LiteLLM model string | `ollama_chat/qwen3.8:27b-mtp-q8_0` | +| Ollama bind | `http://127.0.0.1:11434` | +| `LLM_BASE_URL` | `http://127.0.0.1:11434` (no `/v1`) | +| `OLLAMA_API_BASE` | `http://127.0.0.1:11434` | +| Ollama runtime | native host process, not a container | +| Hardware | AMD Ryzen AI Max+ 395, 64 GB CPU / 64 GB iGPU split | +| Harbor concurrency | `-n 1` | +| Agent context target | 16K–32K, never 256K for these loops | +| Thinking | off for tool loops | +| Docker role | Harbor task sandbox only | + +Legal constraint for any torrent-domain task you create later — authorized +fetches only (Linux ISOs, public domain, content the operator may fetch). +Eval fixtures only. No live indexer or copyrighted-title tasks. + +## Preconditions to collect + +Ask only if missing. Do not invent paths. + +1. Workspace parent. Default `~/src`. +2. Confirm Ollama is already installed and the model tag above is pulled. +3. Confirm Docker Desktop or Engine is installed (needed for Harbor tasks, + not for Ollama). +4. Confirm `git`, `curl`, and Python 3.10+ exist. + +If the operator is on Windows, use Git Bash or an equivalent Unix shell. +PowerShell translation is allowed only for path separators. + +## Step 0 — refuse the wrong job + +If the operator asked to install qBittorrent / Transmission / ClamAV MCP +servers, stop and say this skill is the wrong one. Point them at +`mcp-install-orchestrator`. + +If they asked to run `download-orchestrator` against a live client, stop. +This skill ends when Harbor can import `agent:AutoAgent` and Ollama +answers a tool-call probe. + +## Step 1 — host toolchain + +Run and record output. + +```bash +uname -a +command -v git +command -v curl +command -v python3 +command -v docker +command -v uv || true +command -v ollama +ollama --version +docker version --format '{{.Server.Version}}' 2>/dev/null || docker version +``` + +Install uv if missing: + +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +export PATH="$HOME/.local/bin:$PATH" +``` + +Fail if `ollama` or `docker` is missing. Do not install Ollama inside +Docker to paper over that. + +## Step 2 — native Ollama health + +```bash +curl -sf http://127.0.0.1:11434/api/tags >/tmp/ollama-tags.json +python3 - << 'PY' +import json +tags = json.load(open("/tmp/ollama-tags.json")) +names = [m.get("name") for m in tags.get("models", [])] +print("models:", names) +need = "qwen3.8:27b-mtp-q8_0" +ok = any(n == need or n.startswith(need) for n in names) +print("have_target:", ok) +raise SystemExit(0 if ok else 2) +PY +``` + +If the model is missing: + +```bash +ollama pull qwen3.8:27b-mtp-q8_0 +``` + +Placement check (must be iGPU, not a CPU-only dump): + +```bash +ollama run qwen3.8:27b-mtp-q8_0 "reply with the single word ok" +ollama ps +``` + +`PROCESSOR` / `GPU` columns must show the model resident on GPU. If it is +CPU-only, stop and tell the operator to fix the 64 GB iGPU slice +(Windows Adrenalin VGM, or Linux GTT/UMA) before continuing. + +Tool-call probe with thinking disabled: + +```bash +curl -sf http://127.0.0.1:11434/api/chat -o /tmp/ollama-tool.json -d '{ + "model": "qwen3.8:27b-mtp-q8_0", + "stream": false, + "think": false, + "messages": [{"role": "user", "content": "Call get_time now."}], + "tools": [{ + "type": "function", + "function": { + "name": "get_time", + "description": "Return the current time", + "parameters": {"type": "object", "properties": {}} + } + }] +}' +python3 - << 'PY' +import json +raw = json.load(open("/tmp/ollama-tool.json")) +msg = raw.get("message") or {} +print("keys:", sorted(raw.keys())) +print("has_tool_calls:", bool(msg.get("tool_calls"))) +print("content_preview:", (msg.get("content") or "")[:240]) +if not msg.get("tool_calls"): + raise SystemExit("Ollama did not return tool_calls. Do not start Harbor yet.") +print("ok") +PY +``` + +If this probe fails, do not proceed to Harbor. Report the JSON and stop. + +## Step 3 — clone repos + +```bash +SRC="${SRC:-$HOME/src}" +mkdir -p "$SRC" +cd "$SRC" + +if [ ! -d open-autoagent/.git ]; then + git clone https://github.com/Oncorporation/open-autoagent.git +fi +if [ ! -d secure-torrent-mcp-agent/.git ]; then + git clone https://github.com/Oncorporation/secure-torrent-mcp-agent.git +fi + +cd "$SRC/open-autoagent" +git fetch origin +git checkout main +git pull --ff-only origin main || true +``` + +Create the domain branch if it does not exist: + +```bash +cd "$SRC/open-autoagent" +if git rev-parse --verify domain/secure-torrent >/dev/null 2>&1; then + git checkout domain/secure-torrent +else + git checkout -b domain/secure-torrent +fi +``` + +Vendor the catalog as read-only context. Do not copy it into +`~/.hermes/skills/` from this skill. + +```bash +cd "$SRC/open-autoagent" +mkdir -p vendor docs/domain +rsync -a --delete --exclude .git "$SRC/secure-torrent-mcp-agent/" vendor/secure-torrent-mcp-agent/ +test -f vendor/secure-torrent-mcp-agent/AGENTS.md +test -f vendor/secure-torrent-mcp-agent/workflows/download-then-scan.md +``` + +## Step 4 — write `.env` (never commit) + +```bash +cd "$SRC/open-autoagent" +cat > .env << 'EOF' +LLM_PROVIDER=ollama +MODEL=qwen3.8:27b-mtp-q8_0 +LLM_BASE_URL=http://127.0.0.1:11434 +OLLAMA_API_BASE=http://127.0.0.1:11434 +EOF + +# belt and suspenders for shells that do not auto-load .env +if ! grep -q '^\.env$' .gitignore 2>/dev/null; then + printf '\n.env\nresults.tsv\njobs/\nrun.log\n' >> .gitignore +fi + +set -a +# shellcheck disable=SC1091 +. ./.env +set +a +``` + +Verify `agent.py` still builds `ollama_chat/{MODEL}` when +`LLM_PROVIDER=ollama`. If it does not, stop and show the `create_agent` +block. Do not invent a second model router. + +## Step 5 — patch `program.md` + +Read `program.md`. Apply all of the following. Keep the experiment loop, +`results.tsv` columns, simplicity criterion, and the rule that the +meta-agent must not edit below `FIXED ADAPTER BOUNDARY`. + +Replace the generic directive with: + +```markdown +## Directive + +Build an autonomous download-then-scan harness for authorized torrent +fetches, matching vendor/secure-torrent-mcp-agent. + +Orchestrator split (do not collapse): +- download-orchestrator (no direct torrent/scanner MCP calls) +- torrent-subagent (search, present choices, add one item, return path) +- malware-scan-subagent (scan only named paths) + +Rules: +- Ask before adding when more than one plausible hit exists. +- Scan named paths only. +- Never mark a file safe if ClamAV (or the mock scanner) did not run. +- Authorized content only — Linux ISOs, public domain, operator-authorized. + Refuse everything else. +- If torrent or scanner tools are missing, tell the operator to run + mcp-install-orchestrator. Do not invent servers. + +Model lock: +- LLM_PROVIDER=ollama +- MODEL=qwen3.8:27b-mtp-q8_0 +- Endpoint http://127.0.0.1:11434 +- Do not switch to a cloud model. +- Thinking off for tool loops. +- Harbor concurrency 1. + +Evaluation is Harbor task score (passed, avg_score). +The first run is always the unmodified baseline. +``` + +Delete any sentence that forbids changing the model away from `gpt-5`. + +If `program.md` tells the meta-agent to use `-n 100`, change that example +to `-n 1`. + +## Step 6 — Python env and base image + +```bash +cd "$SRC/open-autoagent" +uv sync +docker build -f Dockerfile.base -t autoagent-base . +``` + +Confirm the agent module imports on the host (this is where LiteLLM +calls Ollama): + +```bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +uv run python - << 'PY' +import os +print("LLM_PROVIDER", os.environ.get("LLM_PROVIDER")) +print("MODEL", os.environ.get("MODEL")) +print("LLM_BASE_URL", os.environ.get("LLM_BASE_URL")) +import agent +print("agent.LLM_PROVIDER", agent.LLM_PROVIDER) +print("agent.MODEL", agent.MODEL) +print("agent.LLM_BASE_URL", agent.LLM_BASE_URL) +print("import_ok") +PY +``` + +Expected: provider `ollama`, model `qwen3.8:27b-mtp-q8_0`, base +`http://127.0.0.1:11434`. + +## Step 7 — tasks directory + +`open-autoagent` ships without tasks. Harbor cannot score an empty +`tasks/` tree. + +If `tasks/` already has Harbor tasks, list them and skip scaffolding. + +If `tasks/` is empty, create **one** smoke task so the loop can run. +Do not create live BitTorrent tasks. + +```text +tasks/choose-before-add/ + task.toml + instruction.md + tests/test.sh + tests/test.py + environment/Dockerfile + files/search_hits.json +``` + +`instruction.md` — search for an authorized Debian netinst fixture. +Two mock hits exist. The agent must list options and must not add a +torrent until a choice is given. + +`files/search_hits.json` — two legal fixture rows (name, size, seeders, +magnet placeholders). No copyrighted titles. + +`environment/Dockerfile`: + +```dockerfile +FROM autoagent-base +COPY files/search_hits.json /opt/fixture/search_hits.json +``` + +`tests/test.sh` must write a 0.0–1.0 reward to the Harbor verifier +log path used by this repo (read an existing Harbor task or Harbor +docs if the exact path differs; commonly `/logs/verifier/reward.txt` +or the path `test.sh` in upstream Harbor examples uses). Score 1.0 +only if the trajectory shows options presented and no add/download +action. + +If you cannot determine the verifier path from Harbor in this repo, +create the task files as stubs, tell the operator the path is +unconfirmed, and still finish steps 8–9. + +## Step 8 — first Harbor run (baseline) + +```bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +rm -rf jobs +mkdir -p jobs +uv run harbor run -p tasks/ --task-name choose-before-add -l 1 -n 1 \ + --agent-import-path agent:AutoAgent -o jobs --job-name latest \ + > run.log 2>&1 +``` + +If `choose-before-add` does not exist, run whatever single task is +present instead of inventing `-n 100`. + +After the run: + +```bash +tail -n 80 run.log +ls jobs | head +ollama ps +``` + +Diagnose from `run.log` and job trajectories. Common failures: + +| Symptom | Fix | +|---|---| +| connection refused 11434 | Ollama is not running on the host | +| tried `host.docker.internal` | revert `.env` to `127.0.0.1` | +| 404 model | tag mismatch; `ollama list` | +| long think, no tools | thinking leaked; keep think off; check LiteLLM version | +| GPU empty, CPU pegged | iGPU slice not 64 GB | +| Harbor `-n` greater than 1 | rerun with `-n 1` | + +## Step 9 — tell the operator how to start the meta-loop + +Do not start an unsupervised overnight rewrite unless they ask. +Give them this exact prompt to paste into a new Hermes session +started from `$SRC/open-autoagent`: + +```text +Read program.md and vendor/secure-torrent-mcp-agent/AGENTS.md. +Use the Ollama model in .env (qwen3.8:27b-mtp-q8_0 at 127.0.0.1:11434). +Establish an unmodified baseline first. +Then propose one harness change above the FIXED ADAPTER BOUNDARY. +``` + +Remind them: + +- Edit only above `FIXED ADAPTER BOUNDARY` in `agent.py`. +- Log every experiment in `results.tsv`. +- Keep or revert on score, not vibes. +- Specialized tools beat a single `run_shell`. +- Do not merge qBittorrent and Transmission into one tool. + +## Done criteria + +All must be true before you declare success: + +- [ ] `curl http://127.0.0.1:11434/api/tags` works +- [ ] `qwen3.8:27b-mtp-q8_0` is present +- [ ] `ollama ps` shows GPU residency +- [ ] tool-call probe returned `tool_calls` +- [ ] `open-autoagent` is on `domain/secure-torrent` +- [ ] `.env` has the locked values and is gitignored +- [ ] `program.md` no longer locks `gpt-5` +- [ ] `uv sync` and `autoagent-base` image succeeded +- [ ] `agent` imports with provider `ollama` +- [ ] at least one Harbor command was attempted or a stub task exists + +## What you must not do + +- Do not `docker run ollama`. +- Do not set `LLM_BASE_URL=http://host.docker.internal:11434`. +- Do not append `/v1` for this LiteLLM Ollama provider. +- Do not change the model tag unless the operator names a new tag. +- Do not commit `.env`, Web UI passwords, or `VIRUSTOTAL_API_KEY`. +- Do not flatten `secure-torrent-mcp-agent` into `~/.hermes/skills/` + from this skill. +- Do not start live downloads or indexer searches as part of setup. diff --git a/setup/harness/hermes/SKILL.md b/setup/harness/hermes/SKILL.md new file mode 100644 index 00000000..d14f0248 --- /dev/null +++ b/setup/harness/hermes/SKILL.md @@ -0,0 +1,437 @@ +--- +name: open-autoagent-ollama-setup +description: Set up Oncorporation open-autoagent on a host-native Ollama daemon for Harbor harness experiments. Use when the user says set up open-autoagent, wire Ollama into AutoAgent, run Harbor on the Ryzen AI Max Plus 395, or start the secure-torrent domain branch. Do not use for installing torrent MCP servers or running download-orchestrator. +license: MIT +metadata: + hermes: + tags: + - open-autoagent + - ollama + - harbor + - harness + category: mcp-install + version: "1.0.0" + hardware: AMD Ryzen AI Max+ 395 64GB-64GB + ollama_model: qwen3.8:27b-mtp-q8_0 +--- + +# Set up open-autoagent on host-native Ollama + +You are running this procedure on the operator machine. Execute the steps +in order. Stop on the first failed check. Do not skip smoke tests. Do not +put Ollama in Docker. Do not point LiteLLM at `host.docker.internal`. + +This skill only provisions the **open-autoagent Harbor loop** against a +**native Ollama daemon**. Torrent MCP install and `download-orchestrator` +are a later step (`mcp-install-orchestrator` in +`Oncorporation/secure-torrent-mcp-agent`). + +## Locked settings from the project session + +Treat these as the source of truth unless the operator explicitly overrides +them in the current turn. + +| Key | Value | +|---|---| +| Repo | `https://github.com/Oncorporation/open-autoagent` | +| Domain catalog (read-only context) | `https://github.com/Oncorporation/secure-torrent-mcp-agent` | +| Domain branch | `domain/secure-torrent` | +| LLM provider | `ollama` | +| Model tag | `qwen3.8:27b-mtp-q8_0` | +| LiteLLM model string | `ollama_chat/qwen3.8:27b-mtp-q8_0` | +| Ollama bind | `http://127.0.0.1:11434` | +| `LLM_BASE_URL` | `http://127.0.0.1:11434` (no `/v1`) | +| `OLLAMA_API_BASE` | `http://127.0.0.1:11434` | +| Ollama runtime | native host process, not a container | +| Hardware | AMD Ryzen AI Max+ 395, 64 GB CPU / 64 GB iGPU split | +| Harbor concurrency | `-n 1` | +| Agent context target | 16K–32K, never 256K for these loops | +| Thinking | off for tool loops | +| Docker role | Harbor task sandbox only | + +Legal constraint for any torrent-domain task you create later — authorized +fetches only (Linux ISOs, public domain, content the operator may fetch). +Eval fixtures only. No live indexer or copyrighted-title tasks. + +## Preconditions to collect + +Ask only if missing. Do not invent paths. + +1. Workspace parent. Default `~/src`. +2. Confirm Ollama is already installed and the model tag above is pulled. +3. Confirm Docker Desktop or Engine is installed (needed for Harbor tasks, + not for Ollama). +4. Confirm `git`, `curl`, and Python 3.10+ exist. + +If the operator is on Windows, use Git Bash or an equivalent Unix shell. +PowerShell translation is allowed only for path separators. + +## Step 0 — refuse the wrong job + +If the operator asked to install qBittorrent / Transmission / ClamAV MCP +servers, stop and say this skill is the wrong one. Point them at +`mcp-install-orchestrator`. + +If they asked to run `download-orchestrator` against a live client, stop. +This skill ends when Harbor can import `agent:AutoAgent` and Ollama +answers a tool-call probe. + +## Step 1 — host toolchain + +Run and record output. + +```bash +uname -a +command -v git +command -v curl +command -v python3 +command -v docker +command -v uv || true +command -v ollama +ollama --version +docker version --format '{{.Server.Version}}' 2>/dev/null || docker version +``` + +Install uv if missing: + +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +export PATH="$HOME/.local/bin:$PATH" +``` + +Fail if `ollama` or `docker` is missing. Do not install Ollama inside +Docker to paper over that. + +## Step 2 — native Ollama health + +```bash +curl -sf http://127.0.0.1:11434/api/tags >/tmp/ollama-tags.json +python3 - << 'PY' +import json +tags = json.load(open("/tmp/ollama-tags.json")) +names = [m.get("name") for m in tags.get("models", [])] +print("models:", names) +need = "qwen3.8:27b-mtp-q8_0" +ok = any(n == need or n.startswith(need) for n in names) +print("have_target:", ok) +raise SystemExit(0 if ok else 2) +PY +``` + +If the model is missing: + +```bash +ollama pull qwen3.8:27b-mtp-q8_0 +``` + +Placement check (must be iGPU, not a CPU-only dump): + +```bash +ollama run qwen3.8:27b-mtp-q8_0 "reply with the single word ok" +ollama ps +``` + +`PROCESSOR` / `GPU` columns must show the model resident on GPU. If it is +CPU-only, stop and tell the operator to fix the 64 GB iGPU slice +(Windows Adrenalin VGM, or Linux GTT/UMA) before continuing. + +Tool-call probe with thinking disabled: + +```bash +curl -sf http://127.0.0.1:11434/api/chat -o /tmp/ollama-tool.json -d '{ + "model": "qwen3.8:27b-mtp-q8_0", + "stream": false, + "think": false, + "messages": [{"role": "user", "content": "Call get_time now."}], + "tools": [{ + "type": "function", + "function": { + "name": "get_time", + "description": "Return the current time", + "parameters": {"type": "object", "properties": {}} + } + }] +}' +python3 - << 'PY' +import json +raw = json.load(open("/tmp/ollama-tool.json")) +msg = raw.get("message") or {} +print("keys:", sorted(raw.keys())) +print("has_tool_calls:", bool(msg.get("tool_calls"))) +print("content_preview:", (msg.get("content") or "")[:240]) +if not msg.get("tool_calls"): + raise SystemExit("Ollama did not return tool_calls. Do not start Harbor yet.") +print("ok") +PY +``` + +If this probe fails, do not proceed to Harbor. Report the JSON and stop. + +## Step 3 — clone repos + +```bash +SRC="${SRC:-$HOME/src}" +mkdir -p "$SRC" +cd "$SRC" + +if [ ! -d open-autoagent/.git ]; then + git clone https://github.com/Oncorporation/open-autoagent.git +fi +if [ ! -d secure-torrent-mcp-agent/.git ]; then + git clone https://github.com/Oncorporation/secure-torrent-mcp-agent.git +fi + +cd "$SRC/open-autoagent" +git fetch origin +git checkout main +git pull --ff-only origin main || true +``` + +Create the domain branch if it does not exist: + +```bash +cd "$SRC/open-autoagent" +if git rev-parse --verify domain/secure-torrent >/dev/null 2>&1; then + git checkout domain/secure-torrent +else + git checkout -b domain/secure-torrent +fi +``` + +Vendor the catalog as read-only context. Do not copy it into +`~/.hermes/skills/` from this skill. + +```bash +cd "$SRC/open-autoagent" +mkdir -p vendor docs/domain +rsync -a --delete --exclude .git "$SRC/secure-torrent-mcp-agent/" vendor/secure-torrent-mcp-agent/ +test -f vendor/secure-torrent-mcp-agent/AGENTS.md +test -f vendor/secure-torrent-mcp-agent/workflows/download-then-scan.md +``` + +## Step 4 — write `.env` (never commit) + +```bash +cd "$SRC/open-autoagent" +cat > .env << 'EOF' +LLM_PROVIDER=ollama +MODEL=qwen3.8:27b-mtp-q8_0 +LLM_BASE_URL=http://127.0.0.1:11434 +OLLAMA_API_BASE=http://127.0.0.1:11434 +EOF + +# belt and suspenders for shells that do not auto-load .env +if ! grep -q '^\.env$' .gitignore 2>/dev/null; then + printf '\n.env\nresults.tsv\njobs/\nrun.log\n' >> .gitignore +fi + +set -a +# shellcheck disable=SC1091 +. ./.env +set +a +``` + +Verify `agent.py` still builds `ollama_chat/{MODEL}` when +`LLM_PROVIDER=ollama`. If it does not, stop and show the `create_agent` +block. Do not invent a second model router. + +## Step 5 — patch `program.md` + +Read `program.md`. Apply all of the following. Keep the experiment loop, +`results.tsv` columns, simplicity criterion, and the rule that the +meta-agent must not edit below `FIXED ADAPTER BOUNDARY`. + +Replace the generic directive with: + +```markdown +## Directive + +Build an autonomous download-then-scan harness for authorized torrent +fetches, matching vendor/secure-torrent-mcp-agent. + +Orchestrator split (do not collapse): +- download-orchestrator (no direct torrent/scanner MCP calls) +- torrent-subagent (search, present choices, add one item, return path) +- malware-scan-subagent (scan only named paths) + +Rules: +- Ask before adding when more than one plausible hit exists. +- Scan named paths only. +- Never mark a file safe if ClamAV (or the mock scanner) did not run. +- Authorized content only — Linux ISOs, public domain, operator-authorized. + Refuse everything else. +- If torrent or scanner tools are missing, tell the operator to run + mcp-install-orchestrator. Do not invent servers. + +Model lock: +- LLM_PROVIDER=ollama +- MODEL=qwen3.8:27b-mtp-q8_0 +- Endpoint http://127.0.0.1:11434 +- Do not switch to a cloud model. +- Thinking off for tool loops. +- Harbor concurrency 1. + +Evaluation is Harbor task score (passed, avg_score). +The first run is always the unmodified baseline. +``` + +Delete any sentence that forbids changing the model away from `gpt-5`. + +If `program.md` tells the meta-agent to use `-n 100`, change that example +to `-n 1`. + +## Step 6 — Python env and base image + +```bash +cd "$SRC/open-autoagent" +uv sync +docker build -f Dockerfile.base -t autoagent-base . +``` + +Confirm the agent module imports on the host (this is where LiteLLM +calls Ollama): + +```bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +uv run python - << 'PY' +import os +print("LLM_PROVIDER", os.environ.get("LLM_PROVIDER")) +print("MODEL", os.environ.get("MODEL")) +print("LLM_BASE_URL", os.environ.get("LLM_BASE_URL")) +import agent +print("agent.LLM_PROVIDER", agent.LLM_PROVIDER) +print("agent.MODEL", agent.MODEL) +print("agent.LLM_BASE_URL", agent.LLM_BASE_URL) +print("import_ok") +PY +``` + +Expected: provider `ollama`, model `qwen3.8:27b-mtp-q8_0`, base +`http://127.0.0.1:11434`. + +## Step 7 — tasks directory + +`open-autoagent` ships without tasks. Harbor cannot score an empty +`tasks/` tree. + +If `tasks/` already has Harbor tasks, list them and skip scaffolding. + +If `tasks/` is empty, create **one** smoke task so the loop can run. +Do not create live BitTorrent tasks. + +```text +tasks/choose-before-add/ + task.toml + instruction.md + tests/test.sh + tests/test.py + environment/Dockerfile + files/search_hits.json +``` + +`instruction.md` — search for an authorized Debian netinst fixture. +Two mock hits exist. The agent must list options and must not add a +torrent until a choice is given. + +`files/search_hits.json` — two legal fixture rows (name, size, seeders, +magnet placeholders). No copyrighted titles. + +`environment/Dockerfile`: + +```dockerfile +FROM autoagent-base +COPY files/search_hits.json /opt/fixture/search_hits.json +``` + +`tests/test.sh` must write a 0.0–1.0 reward to the Harbor verifier +log path used by this repo (read an existing Harbor task or Harbor +docs if the exact path differs; commonly `/logs/verifier/reward.txt` +or the path `test.sh` in upstream Harbor examples uses). Score 1.0 +only if the trajectory shows options presented and no add/download +action. + +If you cannot determine the verifier path from Harbor in this repo, +create the task files as stubs, tell the operator the path is +unconfirmed, and still finish steps 8–9. + +## Step 8 — first Harbor run (baseline) + +```bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +rm -rf jobs +mkdir -p jobs +uv run harbor run -p tasks/ --task-name choose-before-add -l 1 -n 1 \ + --agent-import-path agent:AutoAgent -o jobs --job-name latest \ + > run.log 2>&1 +``` + +If `choose-before-add` does not exist, run whatever single task is +present instead of inventing `-n 100`. + +After the run: + +```bash +tail -n 80 run.log +ls jobs | head +ollama ps +``` + +Diagnose from `run.log` and job trajectories. Common failures: + +| Symptom | Fix | +|---|---| +| connection refused 11434 | Ollama is not running on the host | +| tried `host.docker.internal` | revert `.env` to `127.0.0.1` | +| 404 model | tag mismatch; `ollama list` | +| long think, no tools | thinking leaked; keep think off; check LiteLLM version | +| GPU empty, CPU pegged | iGPU slice not 64 GB | +| Harbor `-n` greater than 1 | rerun with `-n 1` | + +## Step 9 — tell the operator how to start the meta-loop + +Do not start an unsupervised overnight rewrite unless they ask. +Give them this exact prompt to paste into a new Hermes session +started from `$SRC/open-autoagent`: + +```text +Read program.md and vendor/secure-torrent-mcp-agent/AGENTS.md. +Use the Ollama model in .env (qwen3.8:27b-mtp-q8_0 at 127.0.0.1:11434). +Establish an unmodified baseline first. +Then propose one harness change above the FIXED ADAPTER BOUNDARY. +``` + +Remind them: + +- Edit only above `FIXED ADAPTER BOUNDARY` in `agent.py`. +- Log every experiment in `results.tsv`. +- Keep or revert on score, not vibes. +- Specialized tools beat a single `run_shell`. +- Do not merge qBittorrent and Transmission into one tool. + +## Done criteria + +All must be true before you declare success: + +- [ ] `curl http://127.0.0.1:11434/api/tags` works +- [ ] `qwen3.8:27b-mtp-q8_0` is present +- [ ] `ollama ps` shows GPU residency +- [ ] tool-call probe returned `tool_calls` +- [ ] `open-autoagent` is on `domain/secure-torrent` +- [ ] `.env` has the locked values and is gitignored +- [ ] `program.md` no longer locks `gpt-5` +- [ ] `uv sync` and `autoagent-base` image succeeded +- [ ] `agent` imports with provider `ollama` +- [ ] at least one Harbor command was attempted or a stub task exists + +## What you must not do + +- Do not `docker run ollama`. +- Do not set `LLM_BASE_URL=http://host.docker.internal:11434`. +- Do not append `/v1` for this LiteLLM Ollama provider. +- Do not change the model tag unless the operator names a new tag. +- Do not commit `.env`, Web UI passwords, or `VIRUSTOTAL_API_KEY`. +- Do not flatten `secure-torrent-mcp-agent` into `~/.hermes/skills/` + from this skill. +- Do not start live downloads or indexer searches as part of setup. diff --git a/setup/harness/visual-studio/SKILL.md b/setup/harness/visual-studio/SKILL.md new file mode 100644 index 00000000..d14f0248 --- /dev/null +++ b/setup/harness/visual-studio/SKILL.md @@ -0,0 +1,437 @@ +--- +name: open-autoagent-ollama-setup +description: Set up Oncorporation open-autoagent on a host-native Ollama daemon for Harbor harness experiments. Use when the user says set up open-autoagent, wire Ollama into AutoAgent, run Harbor on the Ryzen AI Max Plus 395, or start the secure-torrent domain branch. Do not use for installing torrent MCP servers or running download-orchestrator. +license: MIT +metadata: + hermes: + tags: + - open-autoagent + - ollama + - harbor + - harness + category: mcp-install + version: "1.0.0" + hardware: AMD Ryzen AI Max+ 395 64GB-64GB + ollama_model: qwen3.8:27b-mtp-q8_0 +--- + +# Set up open-autoagent on host-native Ollama + +You are running this procedure on the operator machine. Execute the steps +in order. Stop on the first failed check. Do not skip smoke tests. Do not +put Ollama in Docker. Do not point LiteLLM at `host.docker.internal`. + +This skill only provisions the **open-autoagent Harbor loop** against a +**native Ollama daemon**. Torrent MCP install and `download-orchestrator` +are a later step (`mcp-install-orchestrator` in +`Oncorporation/secure-torrent-mcp-agent`). + +## Locked settings from the project session + +Treat these as the source of truth unless the operator explicitly overrides +them in the current turn. + +| Key | Value | +|---|---| +| Repo | `https://github.com/Oncorporation/open-autoagent` | +| Domain catalog (read-only context) | `https://github.com/Oncorporation/secure-torrent-mcp-agent` | +| Domain branch | `domain/secure-torrent` | +| LLM provider | `ollama` | +| Model tag | `qwen3.8:27b-mtp-q8_0` | +| LiteLLM model string | `ollama_chat/qwen3.8:27b-mtp-q8_0` | +| Ollama bind | `http://127.0.0.1:11434` | +| `LLM_BASE_URL` | `http://127.0.0.1:11434` (no `/v1`) | +| `OLLAMA_API_BASE` | `http://127.0.0.1:11434` | +| Ollama runtime | native host process, not a container | +| Hardware | AMD Ryzen AI Max+ 395, 64 GB CPU / 64 GB iGPU split | +| Harbor concurrency | `-n 1` | +| Agent context target | 16K–32K, never 256K for these loops | +| Thinking | off for tool loops | +| Docker role | Harbor task sandbox only | + +Legal constraint for any torrent-domain task you create later — authorized +fetches only (Linux ISOs, public domain, content the operator may fetch). +Eval fixtures only. No live indexer or copyrighted-title tasks. + +## Preconditions to collect + +Ask only if missing. Do not invent paths. + +1. Workspace parent. Default `~/src`. +2. Confirm Ollama is already installed and the model tag above is pulled. +3. Confirm Docker Desktop or Engine is installed (needed for Harbor tasks, + not for Ollama). +4. Confirm `git`, `curl`, and Python 3.10+ exist. + +If the operator is on Windows, use Git Bash or an equivalent Unix shell. +PowerShell translation is allowed only for path separators. + +## Step 0 — refuse the wrong job + +If the operator asked to install qBittorrent / Transmission / ClamAV MCP +servers, stop and say this skill is the wrong one. Point them at +`mcp-install-orchestrator`. + +If they asked to run `download-orchestrator` against a live client, stop. +This skill ends when Harbor can import `agent:AutoAgent` and Ollama +answers a tool-call probe. + +## Step 1 — host toolchain + +Run and record output. + +```bash +uname -a +command -v git +command -v curl +command -v python3 +command -v docker +command -v uv || true +command -v ollama +ollama --version +docker version --format '{{.Server.Version}}' 2>/dev/null || docker version +``` + +Install uv if missing: + +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +export PATH="$HOME/.local/bin:$PATH" +``` + +Fail if `ollama` or `docker` is missing. Do not install Ollama inside +Docker to paper over that. + +## Step 2 — native Ollama health + +```bash +curl -sf http://127.0.0.1:11434/api/tags >/tmp/ollama-tags.json +python3 - << 'PY' +import json +tags = json.load(open("/tmp/ollama-tags.json")) +names = [m.get("name") for m in tags.get("models", [])] +print("models:", names) +need = "qwen3.8:27b-mtp-q8_0" +ok = any(n == need or n.startswith(need) for n in names) +print("have_target:", ok) +raise SystemExit(0 if ok else 2) +PY +``` + +If the model is missing: + +```bash +ollama pull qwen3.8:27b-mtp-q8_0 +``` + +Placement check (must be iGPU, not a CPU-only dump): + +```bash +ollama run qwen3.8:27b-mtp-q8_0 "reply with the single word ok" +ollama ps +``` + +`PROCESSOR` / `GPU` columns must show the model resident on GPU. If it is +CPU-only, stop and tell the operator to fix the 64 GB iGPU slice +(Windows Adrenalin VGM, or Linux GTT/UMA) before continuing. + +Tool-call probe with thinking disabled: + +```bash +curl -sf http://127.0.0.1:11434/api/chat -o /tmp/ollama-tool.json -d '{ + "model": "qwen3.8:27b-mtp-q8_0", + "stream": false, + "think": false, + "messages": [{"role": "user", "content": "Call get_time now."}], + "tools": [{ + "type": "function", + "function": { + "name": "get_time", + "description": "Return the current time", + "parameters": {"type": "object", "properties": {}} + } + }] +}' +python3 - << 'PY' +import json +raw = json.load(open("/tmp/ollama-tool.json")) +msg = raw.get("message") or {} +print("keys:", sorted(raw.keys())) +print("has_tool_calls:", bool(msg.get("tool_calls"))) +print("content_preview:", (msg.get("content") or "")[:240]) +if not msg.get("tool_calls"): + raise SystemExit("Ollama did not return tool_calls. Do not start Harbor yet.") +print("ok") +PY +``` + +If this probe fails, do not proceed to Harbor. Report the JSON and stop. + +## Step 3 — clone repos + +```bash +SRC="${SRC:-$HOME/src}" +mkdir -p "$SRC" +cd "$SRC" + +if [ ! -d open-autoagent/.git ]; then + git clone https://github.com/Oncorporation/open-autoagent.git +fi +if [ ! -d secure-torrent-mcp-agent/.git ]; then + git clone https://github.com/Oncorporation/secure-torrent-mcp-agent.git +fi + +cd "$SRC/open-autoagent" +git fetch origin +git checkout main +git pull --ff-only origin main || true +``` + +Create the domain branch if it does not exist: + +```bash +cd "$SRC/open-autoagent" +if git rev-parse --verify domain/secure-torrent >/dev/null 2>&1; then + git checkout domain/secure-torrent +else + git checkout -b domain/secure-torrent +fi +``` + +Vendor the catalog as read-only context. Do not copy it into +`~/.hermes/skills/` from this skill. + +```bash +cd "$SRC/open-autoagent" +mkdir -p vendor docs/domain +rsync -a --delete --exclude .git "$SRC/secure-torrent-mcp-agent/" vendor/secure-torrent-mcp-agent/ +test -f vendor/secure-torrent-mcp-agent/AGENTS.md +test -f vendor/secure-torrent-mcp-agent/workflows/download-then-scan.md +``` + +## Step 4 — write `.env` (never commit) + +```bash +cd "$SRC/open-autoagent" +cat > .env << 'EOF' +LLM_PROVIDER=ollama +MODEL=qwen3.8:27b-mtp-q8_0 +LLM_BASE_URL=http://127.0.0.1:11434 +OLLAMA_API_BASE=http://127.0.0.1:11434 +EOF + +# belt and suspenders for shells that do not auto-load .env +if ! grep -q '^\.env$' .gitignore 2>/dev/null; then + printf '\n.env\nresults.tsv\njobs/\nrun.log\n' >> .gitignore +fi + +set -a +# shellcheck disable=SC1091 +. ./.env +set +a +``` + +Verify `agent.py` still builds `ollama_chat/{MODEL}` when +`LLM_PROVIDER=ollama`. If it does not, stop and show the `create_agent` +block. Do not invent a second model router. + +## Step 5 — patch `program.md` + +Read `program.md`. Apply all of the following. Keep the experiment loop, +`results.tsv` columns, simplicity criterion, and the rule that the +meta-agent must not edit below `FIXED ADAPTER BOUNDARY`. + +Replace the generic directive with: + +```markdown +## Directive + +Build an autonomous download-then-scan harness for authorized torrent +fetches, matching vendor/secure-torrent-mcp-agent. + +Orchestrator split (do not collapse): +- download-orchestrator (no direct torrent/scanner MCP calls) +- torrent-subagent (search, present choices, add one item, return path) +- malware-scan-subagent (scan only named paths) + +Rules: +- Ask before adding when more than one plausible hit exists. +- Scan named paths only. +- Never mark a file safe if ClamAV (or the mock scanner) did not run. +- Authorized content only — Linux ISOs, public domain, operator-authorized. + Refuse everything else. +- If torrent or scanner tools are missing, tell the operator to run + mcp-install-orchestrator. Do not invent servers. + +Model lock: +- LLM_PROVIDER=ollama +- MODEL=qwen3.8:27b-mtp-q8_0 +- Endpoint http://127.0.0.1:11434 +- Do not switch to a cloud model. +- Thinking off for tool loops. +- Harbor concurrency 1. + +Evaluation is Harbor task score (passed, avg_score). +The first run is always the unmodified baseline. +``` + +Delete any sentence that forbids changing the model away from `gpt-5`. + +If `program.md` tells the meta-agent to use `-n 100`, change that example +to `-n 1`. + +## Step 6 — Python env and base image + +```bash +cd "$SRC/open-autoagent" +uv sync +docker build -f Dockerfile.base -t autoagent-base . +``` + +Confirm the agent module imports on the host (this is where LiteLLM +calls Ollama): + +```bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +uv run python - << 'PY' +import os +print("LLM_PROVIDER", os.environ.get("LLM_PROVIDER")) +print("MODEL", os.environ.get("MODEL")) +print("LLM_BASE_URL", os.environ.get("LLM_BASE_URL")) +import agent +print("agent.LLM_PROVIDER", agent.LLM_PROVIDER) +print("agent.MODEL", agent.MODEL) +print("agent.LLM_BASE_URL", agent.LLM_BASE_URL) +print("import_ok") +PY +``` + +Expected: provider `ollama`, model `qwen3.8:27b-mtp-q8_0`, base +`http://127.0.0.1:11434`. + +## Step 7 — tasks directory + +`open-autoagent` ships without tasks. Harbor cannot score an empty +`tasks/` tree. + +If `tasks/` already has Harbor tasks, list them and skip scaffolding. + +If `tasks/` is empty, create **one** smoke task so the loop can run. +Do not create live BitTorrent tasks. + +```text +tasks/choose-before-add/ + task.toml + instruction.md + tests/test.sh + tests/test.py + environment/Dockerfile + files/search_hits.json +``` + +`instruction.md` — search for an authorized Debian netinst fixture. +Two mock hits exist. The agent must list options and must not add a +torrent until a choice is given. + +`files/search_hits.json` — two legal fixture rows (name, size, seeders, +magnet placeholders). No copyrighted titles. + +`environment/Dockerfile`: + +```dockerfile +FROM autoagent-base +COPY files/search_hits.json /opt/fixture/search_hits.json +``` + +`tests/test.sh` must write a 0.0–1.0 reward to the Harbor verifier +log path used by this repo (read an existing Harbor task or Harbor +docs if the exact path differs; commonly `/logs/verifier/reward.txt` +or the path `test.sh` in upstream Harbor examples uses). Score 1.0 +only if the trajectory shows options presented and no add/download +action. + +If you cannot determine the verifier path from Harbor in this repo, +create the task files as stubs, tell the operator the path is +unconfirmed, and still finish steps 8–9. + +## Step 8 — first Harbor run (baseline) + +```bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +rm -rf jobs +mkdir -p jobs +uv run harbor run -p tasks/ --task-name choose-before-add -l 1 -n 1 \ + --agent-import-path agent:AutoAgent -o jobs --job-name latest \ + > run.log 2>&1 +``` + +If `choose-before-add` does not exist, run whatever single task is +present instead of inventing `-n 100`. + +After the run: + +```bash +tail -n 80 run.log +ls jobs | head +ollama ps +``` + +Diagnose from `run.log` and job trajectories. Common failures: + +| Symptom | Fix | +|---|---| +| connection refused 11434 | Ollama is not running on the host | +| tried `host.docker.internal` | revert `.env` to `127.0.0.1` | +| 404 model | tag mismatch; `ollama list` | +| long think, no tools | thinking leaked; keep think off; check LiteLLM version | +| GPU empty, CPU pegged | iGPU slice not 64 GB | +| Harbor `-n` greater than 1 | rerun with `-n 1` | + +## Step 9 — tell the operator how to start the meta-loop + +Do not start an unsupervised overnight rewrite unless they ask. +Give them this exact prompt to paste into a new Hermes session +started from `$SRC/open-autoagent`: + +```text +Read program.md and vendor/secure-torrent-mcp-agent/AGENTS.md. +Use the Ollama model in .env (qwen3.8:27b-mtp-q8_0 at 127.0.0.1:11434). +Establish an unmodified baseline first. +Then propose one harness change above the FIXED ADAPTER BOUNDARY. +``` + +Remind them: + +- Edit only above `FIXED ADAPTER BOUNDARY` in `agent.py`. +- Log every experiment in `results.tsv`. +- Keep or revert on score, not vibes. +- Specialized tools beat a single `run_shell`. +- Do not merge qBittorrent and Transmission into one tool. + +## Done criteria + +All must be true before you declare success: + +- [ ] `curl http://127.0.0.1:11434/api/tags` works +- [ ] `qwen3.8:27b-mtp-q8_0` is present +- [ ] `ollama ps` shows GPU residency +- [ ] tool-call probe returned `tool_calls` +- [ ] `open-autoagent` is on `domain/secure-torrent` +- [ ] `.env` has the locked values and is gitignored +- [ ] `program.md` no longer locks `gpt-5` +- [ ] `uv sync` and `autoagent-base` image succeeded +- [ ] `agent` imports with provider `ollama` +- [ ] at least one Harbor command was attempted or a stub task exists + +## What you must not do + +- Do not `docker run ollama`. +- Do not set `LLM_BASE_URL=http://host.docker.internal:11434`. +- Do not append `/v1` for this LiteLLM Ollama provider. +- Do not change the model tag unless the operator names a new tag. +- Do not commit `.env`, Web UI passwords, or `VIRUSTOTAL_API_KEY`. +- Do not flatten `secure-torrent-mcp-agent` into `~/.hermes/skills/` + from this skill. +- Do not start live downloads or indexer searches as part of setup. diff --git a/setup/harness/vscode/SKILL.md b/setup/harness/vscode/SKILL.md new file mode 100644 index 00000000..d14f0248 --- /dev/null +++ b/setup/harness/vscode/SKILL.md @@ -0,0 +1,437 @@ +--- +name: open-autoagent-ollama-setup +description: Set up Oncorporation open-autoagent on a host-native Ollama daemon for Harbor harness experiments. Use when the user says set up open-autoagent, wire Ollama into AutoAgent, run Harbor on the Ryzen AI Max Plus 395, or start the secure-torrent domain branch. Do not use for installing torrent MCP servers or running download-orchestrator. +license: MIT +metadata: + hermes: + tags: + - open-autoagent + - ollama + - harbor + - harness + category: mcp-install + version: "1.0.0" + hardware: AMD Ryzen AI Max+ 395 64GB-64GB + ollama_model: qwen3.8:27b-mtp-q8_0 +--- + +# Set up open-autoagent on host-native Ollama + +You are running this procedure on the operator machine. Execute the steps +in order. Stop on the first failed check. Do not skip smoke tests. Do not +put Ollama in Docker. Do not point LiteLLM at `host.docker.internal`. + +This skill only provisions the **open-autoagent Harbor loop** against a +**native Ollama daemon**. Torrent MCP install and `download-orchestrator` +are a later step (`mcp-install-orchestrator` in +`Oncorporation/secure-torrent-mcp-agent`). + +## Locked settings from the project session + +Treat these as the source of truth unless the operator explicitly overrides +them in the current turn. + +| Key | Value | +|---|---| +| Repo | `https://github.com/Oncorporation/open-autoagent` | +| Domain catalog (read-only context) | `https://github.com/Oncorporation/secure-torrent-mcp-agent` | +| Domain branch | `domain/secure-torrent` | +| LLM provider | `ollama` | +| Model tag | `qwen3.8:27b-mtp-q8_0` | +| LiteLLM model string | `ollama_chat/qwen3.8:27b-mtp-q8_0` | +| Ollama bind | `http://127.0.0.1:11434` | +| `LLM_BASE_URL` | `http://127.0.0.1:11434` (no `/v1`) | +| `OLLAMA_API_BASE` | `http://127.0.0.1:11434` | +| Ollama runtime | native host process, not a container | +| Hardware | AMD Ryzen AI Max+ 395, 64 GB CPU / 64 GB iGPU split | +| Harbor concurrency | `-n 1` | +| Agent context target | 16K–32K, never 256K for these loops | +| Thinking | off for tool loops | +| Docker role | Harbor task sandbox only | + +Legal constraint for any torrent-domain task you create later — authorized +fetches only (Linux ISOs, public domain, content the operator may fetch). +Eval fixtures only. No live indexer or copyrighted-title tasks. + +## Preconditions to collect + +Ask only if missing. Do not invent paths. + +1. Workspace parent. Default `~/src`. +2. Confirm Ollama is already installed and the model tag above is pulled. +3. Confirm Docker Desktop or Engine is installed (needed for Harbor tasks, + not for Ollama). +4. Confirm `git`, `curl`, and Python 3.10+ exist. + +If the operator is on Windows, use Git Bash or an equivalent Unix shell. +PowerShell translation is allowed only for path separators. + +## Step 0 — refuse the wrong job + +If the operator asked to install qBittorrent / Transmission / ClamAV MCP +servers, stop and say this skill is the wrong one. Point them at +`mcp-install-orchestrator`. + +If they asked to run `download-orchestrator` against a live client, stop. +This skill ends when Harbor can import `agent:AutoAgent` and Ollama +answers a tool-call probe. + +## Step 1 — host toolchain + +Run and record output. + +```bash +uname -a +command -v git +command -v curl +command -v python3 +command -v docker +command -v uv || true +command -v ollama +ollama --version +docker version --format '{{.Server.Version}}' 2>/dev/null || docker version +``` + +Install uv if missing: + +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +export PATH="$HOME/.local/bin:$PATH" +``` + +Fail if `ollama` or `docker` is missing. Do not install Ollama inside +Docker to paper over that. + +## Step 2 — native Ollama health + +```bash +curl -sf http://127.0.0.1:11434/api/tags >/tmp/ollama-tags.json +python3 - << 'PY' +import json +tags = json.load(open("/tmp/ollama-tags.json")) +names = [m.get("name") for m in tags.get("models", [])] +print("models:", names) +need = "qwen3.8:27b-mtp-q8_0" +ok = any(n == need or n.startswith(need) for n in names) +print("have_target:", ok) +raise SystemExit(0 if ok else 2) +PY +``` + +If the model is missing: + +```bash +ollama pull qwen3.8:27b-mtp-q8_0 +``` + +Placement check (must be iGPU, not a CPU-only dump): + +```bash +ollama run qwen3.8:27b-mtp-q8_0 "reply with the single word ok" +ollama ps +``` + +`PROCESSOR` / `GPU` columns must show the model resident on GPU. If it is +CPU-only, stop and tell the operator to fix the 64 GB iGPU slice +(Windows Adrenalin VGM, or Linux GTT/UMA) before continuing. + +Tool-call probe with thinking disabled: + +```bash +curl -sf http://127.0.0.1:11434/api/chat -o /tmp/ollama-tool.json -d '{ + "model": "qwen3.8:27b-mtp-q8_0", + "stream": false, + "think": false, + "messages": [{"role": "user", "content": "Call get_time now."}], + "tools": [{ + "type": "function", + "function": { + "name": "get_time", + "description": "Return the current time", + "parameters": {"type": "object", "properties": {}} + } + }] +}' +python3 - << 'PY' +import json +raw = json.load(open("/tmp/ollama-tool.json")) +msg = raw.get("message") or {} +print("keys:", sorted(raw.keys())) +print("has_tool_calls:", bool(msg.get("tool_calls"))) +print("content_preview:", (msg.get("content") or "")[:240]) +if not msg.get("tool_calls"): + raise SystemExit("Ollama did not return tool_calls. Do not start Harbor yet.") +print("ok") +PY +``` + +If this probe fails, do not proceed to Harbor. Report the JSON and stop. + +## Step 3 — clone repos + +```bash +SRC="${SRC:-$HOME/src}" +mkdir -p "$SRC" +cd "$SRC" + +if [ ! -d open-autoagent/.git ]; then + git clone https://github.com/Oncorporation/open-autoagent.git +fi +if [ ! -d secure-torrent-mcp-agent/.git ]; then + git clone https://github.com/Oncorporation/secure-torrent-mcp-agent.git +fi + +cd "$SRC/open-autoagent" +git fetch origin +git checkout main +git pull --ff-only origin main || true +``` + +Create the domain branch if it does not exist: + +```bash +cd "$SRC/open-autoagent" +if git rev-parse --verify domain/secure-torrent >/dev/null 2>&1; then + git checkout domain/secure-torrent +else + git checkout -b domain/secure-torrent +fi +``` + +Vendor the catalog as read-only context. Do not copy it into +`~/.hermes/skills/` from this skill. + +```bash +cd "$SRC/open-autoagent" +mkdir -p vendor docs/domain +rsync -a --delete --exclude .git "$SRC/secure-torrent-mcp-agent/" vendor/secure-torrent-mcp-agent/ +test -f vendor/secure-torrent-mcp-agent/AGENTS.md +test -f vendor/secure-torrent-mcp-agent/workflows/download-then-scan.md +``` + +## Step 4 — write `.env` (never commit) + +```bash +cd "$SRC/open-autoagent" +cat > .env << 'EOF' +LLM_PROVIDER=ollama +MODEL=qwen3.8:27b-mtp-q8_0 +LLM_BASE_URL=http://127.0.0.1:11434 +OLLAMA_API_BASE=http://127.0.0.1:11434 +EOF + +# belt and suspenders for shells that do not auto-load .env +if ! grep -q '^\.env$' .gitignore 2>/dev/null; then + printf '\n.env\nresults.tsv\njobs/\nrun.log\n' >> .gitignore +fi + +set -a +# shellcheck disable=SC1091 +. ./.env +set +a +``` + +Verify `agent.py` still builds `ollama_chat/{MODEL}` when +`LLM_PROVIDER=ollama`. If it does not, stop and show the `create_agent` +block. Do not invent a second model router. + +## Step 5 — patch `program.md` + +Read `program.md`. Apply all of the following. Keep the experiment loop, +`results.tsv` columns, simplicity criterion, and the rule that the +meta-agent must not edit below `FIXED ADAPTER BOUNDARY`. + +Replace the generic directive with: + +```markdown +## Directive + +Build an autonomous download-then-scan harness for authorized torrent +fetches, matching vendor/secure-torrent-mcp-agent. + +Orchestrator split (do not collapse): +- download-orchestrator (no direct torrent/scanner MCP calls) +- torrent-subagent (search, present choices, add one item, return path) +- malware-scan-subagent (scan only named paths) + +Rules: +- Ask before adding when more than one plausible hit exists. +- Scan named paths only. +- Never mark a file safe if ClamAV (or the mock scanner) did not run. +- Authorized content only — Linux ISOs, public domain, operator-authorized. + Refuse everything else. +- If torrent or scanner tools are missing, tell the operator to run + mcp-install-orchestrator. Do not invent servers. + +Model lock: +- LLM_PROVIDER=ollama +- MODEL=qwen3.8:27b-mtp-q8_0 +- Endpoint http://127.0.0.1:11434 +- Do not switch to a cloud model. +- Thinking off for tool loops. +- Harbor concurrency 1. + +Evaluation is Harbor task score (passed, avg_score). +The first run is always the unmodified baseline. +``` + +Delete any sentence that forbids changing the model away from `gpt-5`. + +If `program.md` tells the meta-agent to use `-n 100`, change that example +to `-n 1`. + +## Step 6 — Python env and base image + +```bash +cd "$SRC/open-autoagent" +uv sync +docker build -f Dockerfile.base -t autoagent-base . +``` + +Confirm the agent module imports on the host (this is where LiteLLM +calls Ollama): + +```bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +uv run python - << 'PY' +import os +print("LLM_PROVIDER", os.environ.get("LLM_PROVIDER")) +print("MODEL", os.environ.get("MODEL")) +print("LLM_BASE_URL", os.environ.get("LLM_BASE_URL")) +import agent +print("agent.LLM_PROVIDER", agent.LLM_PROVIDER) +print("agent.MODEL", agent.MODEL) +print("agent.LLM_BASE_URL", agent.LLM_BASE_URL) +print("import_ok") +PY +``` + +Expected: provider `ollama`, model `qwen3.8:27b-mtp-q8_0`, base +`http://127.0.0.1:11434`. + +## Step 7 — tasks directory + +`open-autoagent` ships without tasks. Harbor cannot score an empty +`tasks/` tree. + +If `tasks/` already has Harbor tasks, list them and skip scaffolding. + +If `tasks/` is empty, create **one** smoke task so the loop can run. +Do not create live BitTorrent tasks. + +```text +tasks/choose-before-add/ + task.toml + instruction.md + tests/test.sh + tests/test.py + environment/Dockerfile + files/search_hits.json +``` + +`instruction.md` — search for an authorized Debian netinst fixture. +Two mock hits exist. The agent must list options and must not add a +torrent until a choice is given. + +`files/search_hits.json` — two legal fixture rows (name, size, seeders, +magnet placeholders). No copyrighted titles. + +`environment/Dockerfile`: + +```dockerfile +FROM autoagent-base +COPY files/search_hits.json /opt/fixture/search_hits.json +``` + +`tests/test.sh` must write a 0.0–1.0 reward to the Harbor verifier +log path used by this repo (read an existing Harbor task or Harbor +docs if the exact path differs; commonly `/logs/verifier/reward.txt` +or the path `test.sh` in upstream Harbor examples uses). Score 1.0 +only if the trajectory shows options presented and no add/download +action. + +If you cannot determine the verifier path from Harbor in this repo, +create the task files as stubs, tell the operator the path is +unconfirmed, and still finish steps 8–9. + +## Step 8 — first Harbor run (baseline) + +```bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +rm -rf jobs +mkdir -p jobs +uv run harbor run -p tasks/ --task-name choose-before-add -l 1 -n 1 \ + --agent-import-path agent:AutoAgent -o jobs --job-name latest \ + > run.log 2>&1 +``` + +If `choose-before-add` does not exist, run whatever single task is +present instead of inventing `-n 100`. + +After the run: + +```bash +tail -n 80 run.log +ls jobs | head +ollama ps +``` + +Diagnose from `run.log` and job trajectories. Common failures: + +| Symptom | Fix | +|---|---| +| connection refused 11434 | Ollama is not running on the host | +| tried `host.docker.internal` | revert `.env` to `127.0.0.1` | +| 404 model | tag mismatch; `ollama list` | +| long think, no tools | thinking leaked; keep think off; check LiteLLM version | +| GPU empty, CPU pegged | iGPU slice not 64 GB | +| Harbor `-n` greater than 1 | rerun with `-n 1` | + +## Step 9 — tell the operator how to start the meta-loop + +Do not start an unsupervised overnight rewrite unless they ask. +Give them this exact prompt to paste into a new Hermes session +started from `$SRC/open-autoagent`: + +```text +Read program.md and vendor/secure-torrent-mcp-agent/AGENTS.md. +Use the Ollama model in .env (qwen3.8:27b-mtp-q8_0 at 127.0.0.1:11434). +Establish an unmodified baseline first. +Then propose one harness change above the FIXED ADAPTER BOUNDARY. +``` + +Remind them: + +- Edit only above `FIXED ADAPTER BOUNDARY` in `agent.py`. +- Log every experiment in `results.tsv`. +- Keep or revert on score, not vibes. +- Specialized tools beat a single `run_shell`. +- Do not merge qBittorrent and Transmission into one tool. + +## Done criteria + +All must be true before you declare success: + +- [ ] `curl http://127.0.0.1:11434/api/tags` works +- [ ] `qwen3.8:27b-mtp-q8_0` is present +- [ ] `ollama ps` shows GPU residency +- [ ] tool-call probe returned `tool_calls` +- [ ] `open-autoagent` is on `domain/secure-torrent` +- [ ] `.env` has the locked values and is gitignored +- [ ] `program.md` no longer locks `gpt-5` +- [ ] `uv sync` and `autoagent-base` image succeeded +- [ ] `agent` imports with provider `ollama` +- [ ] at least one Harbor command was attempted or a stub task exists + +## What you must not do + +- Do not `docker run ollama`. +- Do not set `LLM_BASE_URL=http://host.docker.internal:11434`. +- Do not append `/v1` for this LiteLLM Ollama provider. +- Do not change the model tag unless the operator names a new tag. +- Do not commit `.env`, Web UI passwords, or `VIRUSTOTAL_API_KEY`. +- Do not flatten `secure-torrent-mcp-agent` into `~/.hermes/skills/` + from this skill. +- Do not start live downloads or indexer searches as part of setup. diff --git a/setup/install.ps1 b/setup/install.ps1 new file mode 100644 index 00000000..2c2ae340 --- /dev/null +++ b/setup/install.ps1 @@ -0,0 +1,174 @@ +#Requires -Version 5.1 +<# +.SYNOPSIS + Installs the open-autoagent-ollama-setup skill for your AI harness. +.DESCRIPTION + Prompts for harness selection and copies the pre-built SKILL.md to the + correct location for that harness. Additional harnesses can be added by + creating a subfolder under setup\harness\ and updating the switch below. +.EXAMPLE + .\setup\install.ps1 +#> + +$ErrorActionPreference = "Stop" + +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$RepoRoot = Split-Path -Parent $ScriptDir +$HarnessDir = Join-Path $ScriptDir "harness" +$SkillName = "open-autoagent-ollama-setup" +$UserHome = $env:USERPROFILE +$ConfigFile = Join-Path $ScriptDir ".skill-config.json" + +# Load config if it exists +if (Test-Path $ConfigFile) { + $config = Get-Content -Raw $ConfigFile | ConvertFrom-Json + $mainRepo = $config.mainRepo + $model = $config.model + $ollamaEndpoint = $config.ollamaEndpoint + $hardware = $config.hardware + $domainRepo = $config.domainRepo + $domainBranch = $config.domainBranch +} else { + # Defaults + $mainRepo = "https://github.com/Oncorporation/open-autoagent" + $model = "qwen3.8:27b-mtp-q8_0" + $ollamaEndpoint = "http://127.0.0.1:11434" + $hardware = "AMD Ryzen AI Max+ 395 64GB-64GB" + $domainRepo = "https://github.com/Oncorporation/secure-torrent-mcp-agent" + $domainBranch = "domain/secure-torrent" +} + +# -- menu ---------------------------------------------------------------------- +Write-Host "" +Write-Host " open-autoagent-ollama-setup -- Skill Installer" -ForegroundColor Cyan +Write-Host " --------------------------------------------------" -ForegroundColor DarkGray +Write-Host "" +Write-Host " Select your AI harness:" -ForegroundColor White +Write-Host " 1) Hermes" +Write-Host " 2) Claude Code (project-level: \.claude\)" +Write-Host " 3) Claude Desktop (user-level: ~\.claude\)" +Write-Host " 4) Cursor (project-level: \.cursor\)" +Write-Host " 5) Grok (user-level: ~\.grok\)" +Write-Host " 6) VS Code + Copilot (project-level: \.vscode\)" +Write-Host " 7) Visual Studio (project-level: \.github\)" +Write-Host "" +Write-Host " (Additional harnesses: add a folder under setup\harness\ and re-run)" -ForegroundColor DarkGray +Write-Host "" + +$choice = "" +while ($choice -notmatch '^[1-7]$') { + $choice = (Read-Host " Enter number [1-7]").Trim() +} + +# -- resolve harness name and install path ------------------------------------- +switch ($choice) { + "1" { + $Harness = "hermes" + $TargetDir = Join-Path $UserHome ".hermes\skills\mcp-install\$SkillName" + } + "2" { + $Harness = "claude-code" + $TargetDir = Join-Path $RepoRoot ".claude\skills\$SkillName" + } + "3" { + $Harness = "claude-desktop" + $TargetDir = Join-Path $UserHome ".claude\skills\$SkillName" + } + "4" { + $Harness = "cursor" + $TargetDir = Join-Path $RepoRoot ".cursor\skills\$SkillName" + } + "5" { + $Harness = "grok" + $TargetDir = Join-Path $UserHome ".grok\skills\$SkillName" + } + "6" { + $Harness = "vscode" + $TargetDir = Join-Path $RepoRoot ".vscode\skills\$SkillName" + } + "7" { + $Harness = "visual-studio" + $TargetDir = Join-Path $RepoRoot ".github\skills\$SkillName" + } +} + +# -- locate and process source ------------------------------------------------ +$SourceFile = Join-Path $HarnessDir "$Harness\SKILL.md" + +# Fall back to template-based generation if no harness-specific file exists +if (-not (Test-Path $SourceFile)) { + $Template = Join-Path $ScriptDir "SKILL.md.template" + if (-not (Test-Path $Template)) { + # Further fallback: use canonical if template missing + $SourceFile = Join-Path $ScriptDir "$SkillName.md" + } else { + # Generate from template on-the-fly + $TempFile = Join-Path $env:TEMP "skill-$Harness-$(Get-Random).md" + $TemplateContent = Get-Content -Raw $Template + $TemplateContent = $TemplateContent -replace '\{\{MAIN_REPO\}\}', $mainRepo + $TemplateContent = $TemplateContent -replace '\{\{MODEL\}\}', $model + $TemplateContent = $TemplateContent -replace '\{\{OLLAMA_ENDPOINT\}\}', $ollamaEndpoint + $TemplateContent = $TemplateContent -replace '\{\{HARDWARE\}\}', $hardware + $TemplateContent = $TemplateContent -replace '\{\{DOMAIN_REPO\}\}', $domainRepo + $TemplateContent = $TemplateContent -replace '\{\{DOMAIN_BRANCH\}\}', $domainBranch + Set-Content -Path $TempFile -Value $TemplateContent + $SourceFile = $TempFile + } +} + +if (-not (Test-Path $SourceFile)) { + Write-Error "Source SKILL.md not found at '$SourceFile'." + exit 1 +} + +# -- confirm ------------------------------------------------------------------- +Write-Host "" +Write-Host " Harness : $Harness" -ForegroundColor Yellow +Write-Host " Source : $SourceFile" -ForegroundColor DarkGray +Write-Host " Target : $TargetDir\SKILL.md" -ForegroundColor Yellow +Write-Host " Model : $model" -ForegroundColor DarkGray +Write-Host " Repo : $mainRepo" -ForegroundColor DarkGray +Write-Host "" + +$confirm = (Read-Host " Proceed? [Y/n]").Trim() +if ($confirm -match '^[Nn]') { + Write-Host " Aborted." -ForegroundColor Red + exit 0 +} + +# -- install ------------------------------------------------------------------- +New-Item -ItemType Directory -Force -Path $TargetDir | Out-Null +Copy-Item -Path $SourceFile -Destination (Join-Path $TargetDir "SKILL.md") -Force + +# Clean up temp file if created +if ($SourceFile -match '\\Temp\\') { + Remove-Item -Path $SourceFile -Force +} + +Write-Host "" +Write-Host " OK Installed: $TargetDir\SKILL.md" -ForegroundColor Green +Write-Host "" + +# -- trigger instructions ------------------------------------------------------ +Write-Host " Next: open $Harness and run the skill:" -ForegroundColor Cyan +switch ($Harness) { + "hermes" { Write-Host " Start a new session (or /reset), then paste:" ; Write-Host " run open-autoagent-ollama-setup" } + "claude-code" { Write-Host " /skill open-autoagent-ollama-setup" } + "claude-desktop" { Write-Host " run the skill named open-autoagent-ollama-setup" } + "cursor" { Write-Host " @open-autoagent-ollama-setup in the Cursor chat" } + "grok" { Write-Host " run open-autoagent-ollama-setup" } + "vscode" { + Write-Host " In Copilot Chat (Ctrl+Shift+I), attach the file then ask:" + Write-Host " #file:.vscode\skills\$SkillName\SKILL.md" + Write-Host " run open-autoagent-ollama-setup" + } + "visual-studio" { + Write-Host " In Copilot Chat (View > GitHub Copilot Chat), attach the file then ask:" + Write-Host " #file:.github\skills\$SkillName\SKILL.md" + Write-Host " run open-autoagent-ollama-setup" + } + default { + throw "Unknown harness '$Harness'. Add a folder under setup\harness\ and a matching arm here." + } +} +Write-Host "" diff --git a/setup/install.sh b/setup/install.sh new file mode 100644 index 00000000..56b168ff --- /dev/null +++ b/setup/install.sh @@ -0,0 +1,155 @@ +#!/usr/bin/env bash +# install.sh — Install open-autoagent-ollama-setup skill for your AI harness. +# +# Usage: bash setup/install.sh +# (or chmod +x setup/install.sh && ./setup/install.sh from repo root) +# +# Additional harnesses: add a subfolder under setup/harness/ and update the +# case block below. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +HARNESS_DIR="$SCRIPT_DIR/harness" +SKILL_NAME="open-autoagent-ollama-setup" +CONFIG_FILE="$SCRIPT_DIR/.skill-config.json" + +# Load config if it exists +if [[ -f "$CONFIG_FILE" ]]; then + MAIN_REPO=$(jq -r '.mainRepo // empty' "$CONFIG_FILE") + MODEL=$(jq -r '.model // empty' "$CONFIG_FILE") + OLLAMA_ENDPOINT=$(jq -r '.ollamaEndpoint // empty' "$CONFIG_FILE") + HARDWARE=$(jq -r '.hardware // empty' "$CONFIG_FILE") + DOMAIN_REPO=$(jq -r '.domainRepo // empty' "$CONFIG_FILE") + DOMAIN_BRANCH=$(jq -r '.domainBranch // empty' "$CONFIG_FILE") +else + # Defaults + MAIN_REPO="https://github.com/Oncorporation/open-autoagent" + MODEL="qwen3.8:27b-mtp-q8_0" + OLLAMA_ENDPOINT="http://127.0.0.1:11434" + HARDWARE="AMD Ryzen AI Max+ 395 64GB-64GB" + DOMAIN_REPO="https://github.com/Oncorporation/secure-torrent-mcp-agent" + DOMAIN_BRANCH="domain/secure-torrent" +fi + +# ── menu ────────────────────────────────────────────────────────────────────── +echo "" +echo " open-autoagent-ollama-setup -- Skill Installer" +echo " --------------------------------------------------" +echo "" +echo " Select your AI harness:" +echo " 1) Hermes" +echo " 2) Claude Code (project-level: /.claude/)" +echo " 3) Claude Desktop (user-level: ~/.claude/)" +echo " 4) Cursor (project-level: /.cursor/)" +echo " 5) Grok (user-level: ~/.grok/)" +echo " 6) VS Code + Copilot (project-level: /.vscode/)" +echo " 7) Visual Studio (project-level: /.github/)" +echo "" +echo " (Additional harnesses: add a folder under setup/harness/ and re-run)" +echo "" + +choice="" +while [[ ! "$choice" =~ ^[1-7]$ ]]; do + read -rp " Enter number [1-7]: " choice +done + +# ── resolve harness name and install path ───────────────────────────────────── +case "$choice" in + 1) HARNESS="hermes"; TARGET_DIR="$HOME/.hermes/skills/mcp-install/$SKILL_NAME" ;; + 2) HARNESS="claude-code"; TARGET_DIR="$REPO_ROOT/.claude/skills/$SKILL_NAME" ;; + 3) HARNESS="claude-desktop"; TARGET_DIR="$HOME/.claude/skills/$SKILL_NAME" ;; + 4) HARNESS="cursor"; TARGET_DIR="$REPO_ROOT/.cursor/skills/$SKILL_NAME" ;; + 5) HARNESS="grok"; TARGET_DIR="$HOME/.grok/skills/$SKILL_NAME" ;; + 6) HARNESS="vscode"; TARGET_DIR="$REPO_ROOT/.vscode/skills/$SKILL_NAME" ;; + 7) HARNESS="visual-studio"; TARGET_DIR="$REPO_ROOT/.github/skills/$SKILL_NAME" ;; +esac + +# ── locate and process source ──────────────────────────────────────────────── +TEMPLATE_FILE="$HARNESS_DIR/$HARNESS/SKILL.md" +HARNESS_SOURCE_FILE="$TEMPLATE_FILE" + +# Fall back to template-based generation if no harness-specific file exists +if [[ ! -f "$HARNESS_SOURCE_FILE" ]]; then + TEMPLATE="$SCRIPT_DIR/SKILL.md.template" + if [[ ! -f "$TEMPLATE" ]]; then + # Further fallback: use canonical if template missing + HARNESS_SOURCE_FILE="$SCRIPT_DIR/$SKILL_NAME.md" + else + # Generate from template on-the-fly + HARNESS_SOURCE_FILE="/tmp/$SKILL_NAME-$HARNESS-$RANDOM.md" + sed \ + -e "s|{{MAIN_REPO}}|$MAIN_REPO|g" \ + -e "s|{{MODEL}}|$MODEL|g" \ + -e "s|{{OLLAMA_ENDPOINT}}|$OLLAMA_ENDPOINT|g" \ + -e "s|{{HARDWARE}}|$HARDWARE|g" \ + -e "s|{{DOMAIN_REPO}}|$DOMAIN_REPO|g" \ + -e "s|{{DOMAIN_BRANCH}}|$DOMAIN_BRANCH|g" \ + "$TEMPLATE" > "$HARNESS_SOURCE_FILE" + fi +fi + +if [[ ! -f "$HARNESS_SOURCE_FILE" ]]; then + echo "ERROR: No source SKILL.md found and no template to process." >&2 + exit 1 +fi + +# ── confirm ─────────────────────────────────────────────────────────────────── +echo "" +echo " Harness : $HARNESS" +echo " Source : $HARNESS_SOURCE_FILE" +echo " Target : $TARGET_DIR/SKILL.md" +echo " Model : $MODEL" +echo " Repo : $MAIN_REPO" +echo "" +read -rp " Proceed? [Y/n]: " confirm +if [[ "$confirm" =~ ^[Nn] ]]; then + echo " Aborted." + exit 0 +fi + +# ── install ─────────────────────────────────────────────────────────────────── +mkdir -p "$TARGET_DIR" +cp -f "$HARNESS_SOURCE_FILE" "$TARGET_DIR/SKILL.md" + +# Clean up temp file if created +if [[ "$HARNESS_SOURCE_FILE" =~ ^/tmp/ ]]; then + rm -f "$HARNESS_SOURCE_FILE" +fi + +echo "" +echo " ✓ Installed: $TARGET_DIR/SKILL.md" +echo "" + +# ── trigger instructions ────────────────────────────────────────────────────── +echo " Next: open $HARNESS and run the skill:" +case "$HARNESS" in + hermes) + echo " Start a new session (or /reset), then paste:" + echo " run open-autoagent-ollama-setup" + ;; + claude-code) + echo " /skill open-autoagent-ollama-setup" + ;; + claude-desktop) + echo " run the skill named open-autoagent-ollama-setup" + ;; + cursor) + echo " @open-autoagent-ollama-setup in the Cursor chat" + ;; + grok) + echo " run open-autoagent-ollama-setup" + ;; + vscode) + echo " In Copilot Chat (Ctrl+Shift+I), attach the file then ask:" + echo " #file:.vscode/skills/$SKILL_NAME/SKILL.md" + echo " run open-autoagent-ollama-setup" + ;; + visual-studio) + echo " In Copilot Chat (View > GitHub Copilot Chat), attach the file then ask:" + echo " #file:.github/skills/$SKILL_NAME/SKILL.md" + echo " run open-autoagent-ollama-setup" + ;; +esac +echo "" diff --git a/setup/open-autoagent-ollama-setup.md b/setup/open-autoagent-ollama-setup.md new file mode 100644 index 00000000..d14f0248 --- /dev/null +++ b/setup/open-autoagent-ollama-setup.md @@ -0,0 +1,437 @@ +--- +name: open-autoagent-ollama-setup +description: Set up Oncorporation open-autoagent on a host-native Ollama daemon for Harbor harness experiments. Use when the user says set up open-autoagent, wire Ollama into AutoAgent, run Harbor on the Ryzen AI Max Plus 395, or start the secure-torrent domain branch. Do not use for installing torrent MCP servers or running download-orchestrator. +license: MIT +metadata: + hermes: + tags: + - open-autoagent + - ollama + - harbor + - harness + category: mcp-install + version: "1.0.0" + hardware: AMD Ryzen AI Max+ 395 64GB-64GB + ollama_model: qwen3.8:27b-mtp-q8_0 +--- + +# Set up open-autoagent on host-native Ollama + +You are running this procedure on the operator machine. Execute the steps +in order. Stop on the first failed check. Do not skip smoke tests. Do not +put Ollama in Docker. Do not point LiteLLM at `host.docker.internal`. + +This skill only provisions the **open-autoagent Harbor loop** against a +**native Ollama daemon**. Torrent MCP install and `download-orchestrator` +are a later step (`mcp-install-orchestrator` in +`Oncorporation/secure-torrent-mcp-agent`). + +## Locked settings from the project session + +Treat these as the source of truth unless the operator explicitly overrides +them in the current turn. + +| Key | Value | +|---|---| +| Repo | `https://github.com/Oncorporation/open-autoagent` | +| Domain catalog (read-only context) | `https://github.com/Oncorporation/secure-torrent-mcp-agent` | +| Domain branch | `domain/secure-torrent` | +| LLM provider | `ollama` | +| Model tag | `qwen3.8:27b-mtp-q8_0` | +| LiteLLM model string | `ollama_chat/qwen3.8:27b-mtp-q8_0` | +| Ollama bind | `http://127.0.0.1:11434` | +| `LLM_BASE_URL` | `http://127.0.0.1:11434` (no `/v1`) | +| `OLLAMA_API_BASE` | `http://127.0.0.1:11434` | +| Ollama runtime | native host process, not a container | +| Hardware | AMD Ryzen AI Max+ 395, 64 GB CPU / 64 GB iGPU split | +| Harbor concurrency | `-n 1` | +| Agent context target | 16K–32K, never 256K for these loops | +| Thinking | off for tool loops | +| Docker role | Harbor task sandbox only | + +Legal constraint for any torrent-domain task you create later — authorized +fetches only (Linux ISOs, public domain, content the operator may fetch). +Eval fixtures only. No live indexer or copyrighted-title tasks. + +## Preconditions to collect + +Ask only if missing. Do not invent paths. + +1. Workspace parent. Default `~/src`. +2. Confirm Ollama is already installed and the model tag above is pulled. +3. Confirm Docker Desktop or Engine is installed (needed for Harbor tasks, + not for Ollama). +4. Confirm `git`, `curl`, and Python 3.10+ exist. + +If the operator is on Windows, use Git Bash or an equivalent Unix shell. +PowerShell translation is allowed only for path separators. + +## Step 0 — refuse the wrong job + +If the operator asked to install qBittorrent / Transmission / ClamAV MCP +servers, stop and say this skill is the wrong one. Point them at +`mcp-install-orchestrator`. + +If they asked to run `download-orchestrator` against a live client, stop. +This skill ends when Harbor can import `agent:AutoAgent` and Ollama +answers a tool-call probe. + +## Step 1 — host toolchain + +Run and record output. + +```bash +uname -a +command -v git +command -v curl +command -v python3 +command -v docker +command -v uv || true +command -v ollama +ollama --version +docker version --format '{{.Server.Version}}' 2>/dev/null || docker version +``` + +Install uv if missing: + +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +export PATH="$HOME/.local/bin:$PATH" +``` + +Fail if `ollama` or `docker` is missing. Do not install Ollama inside +Docker to paper over that. + +## Step 2 — native Ollama health + +```bash +curl -sf http://127.0.0.1:11434/api/tags >/tmp/ollama-tags.json +python3 - << 'PY' +import json +tags = json.load(open("/tmp/ollama-tags.json")) +names = [m.get("name") for m in tags.get("models", [])] +print("models:", names) +need = "qwen3.8:27b-mtp-q8_0" +ok = any(n == need or n.startswith(need) for n in names) +print("have_target:", ok) +raise SystemExit(0 if ok else 2) +PY +``` + +If the model is missing: + +```bash +ollama pull qwen3.8:27b-mtp-q8_0 +``` + +Placement check (must be iGPU, not a CPU-only dump): + +```bash +ollama run qwen3.8:27b-mtp-q8_0 "reply with the single word ok" +ollama ps +``` + +`PROCESSOR` / `GPU` columns must show the model resident on GPU. If it is +CPU-only, stop and tell the operator to fix the 64 GB iGPU slice +(Windows Adrenalin VGM, or Linux GTT/UMA) before continuing. + +Tool-call probe with thinking disabled: + +```bash +curl -sf http://127.0.0.1:11434/api/chat -o /tmp/ollama-tool.json -d '{ + "model": "qwen3.8:27b-mtp-q8_0", + "stream": false, + "think": false, + "messages": [{"role": "user", "content": "Call get_time now."}], + "tools": [{ + "type": "function", + "function": { + "name": "get_time", + "description": "Return the current time", + "parameters": {"type": "object", "properties": {}} + } + }] +}' +python3 - << 'PY' +import json +raw = json.load(open("/tmp/ollama-tool.json")) +msg = raw.get("message") or {} +print("keys:", sorted(raw.keys())) +print("has_tool_calls:", bool(msg.get("tool_calls"))) +print("content_preview:", (msg.get("content") or "")[:240]) +if not msg.get("tool_calls"): + raise SystemExit("Ollama did not return tool_calls. Do not start Harbor yet.") +print("ok") +PY +``` + +If this probe fails, do not proceed to Harbor. Report the JSON and stop. + +## Step 3 — clone repos + +```bash +SRC="${SRC:-$HOME/src}" +mkdir -p "$SRC" +cd "$SRC" + +if [ ! -d open-autoagent/.git ]; then + git clone https://github.com/Oncorporation/open-autoagent.git +fi +if [ ! -d secure-torrent-mcp-agent/.git ]; then + git clone https://github.com/Oncorporation/secure-torrent-mcp-agent.git +fi + +cd "$SRC/open-autoagent" +git fetch origin +git checkout main +git pull --ff-only origin main || true +``` + +Create the domain branch if it does not exist: + +```bash +cd "$SRC/open-autoagent" +if git rev-parse --verify domain/secure-torrent >/dev/null 2>&1; then + git checkout domain/secure-torrent +else + git checkout -b domain/secure-torrent +fi +``` + +Vendor the catalog as read-only context. Do not copy it into +`~/.hermes/skills/` from this skill. + +```bash +cd "$SRC/open-autoagent" +mkdir -p vendor docs/domain +rsync -a --delete --exclude .git "$SRC/secure-torrent-mcp-agent/" vendor/secure-torrent-mcp-agent/ +test -f vendor/secure-torrent-mcp-agent/AGENTS.md +test -f vendor/secure-torrent-mcp-agent/workflows/download-then-scan.md +``` + +## Step 4 — write `.env` (never commit) + +```bash +cd "$SRC/open-autoagent" +cat > .env << 'EOF' +LLM_PROVIDER=ollama +MODEL=qwen3.8:27b-mtp-q8_0 +LLM_BASE_URL=http://127.0.0.1:11434 +OLLAMA_API_BASE=http://127.0.0.1:11434 +EOF + +# belt and suspenders for shells that do not auto-load .env +if ! grep -q '^\.env$' .gitignore 2>/dev/null; then + printf '\n.env\nresults.tsv\njobs/\nrun.log\n' >> .gitignore +fi + +set -a +# shellcheck disable=SC1091 +. ./.env +set +a +``` + +Verify `agent.py` still builds `ollama_chat/{MODEL}` when +`LLM_PROVIDER=ollama`. If it does not, stop and show the `create_agent` +block. Do not invent a second model router. + +## Step 5 — patch `program.md` + +Read `program.md`. Apply all of the following. Keep the experiment loop, +`results.tsv` columns, simplicity criterion, and the rule that the +meta-agent must not edit below `FIXED ADAPTER BOUNDARY`. + +Replace the generic directive with: + +```markdown +## Directive + +Build an autonomous download-then-scan harness for authorized torrent +fetches, matching vendor/secure-torrent-mcp-agent. + +Orchestrator split (do not collapse): +- download-orchestrator (no direct torrent/scanner MCP calls) +- torrent-subagent (search, present choices, add one item, return path) +- malware-scan-subagent (scan only named paths) + +Rules: +- Ask before adding when more than one plausible hit exists. +- Scan named paths only. +- Never mark a file safe if ClamAV (or the mock scanner) did not run. +- Authorized content only — Linux ISOs, public domain, operator-authorized. + Refuse everything else. +- If torrent or scanner tools are missing, tell the operator to run + mcp-install-orchestrator. Do not invent servers. + +Model lock: +- LLM_PROVIDER=ollama +- MODEL=qwen3.8:27b-mtp-q8_0 +- Endpoint http://127.0.0.1:11434 +- Do not switch to a cloud model. +- Thinking off for tool loops. +- Harbor concurrency 1. + +Evaluation is Harbor task score (passed, avg_score). +The first run is always the unmodified baseline. +``` + +Delete any sentence that forbids changing the model away from `gpt-5`. + +If `program.md` tells the meta-agent to use `-n 100`, change that example +to `-n 1`. + +## Step 6 — Python env and base image + +```bash +cd "$SRC/open-autoagent" +uv sync +docker build -f Dockerfile.base -t autoagent-base . +``` + +Confirm the agent module imports on the host (this is where LiteLLM +calls Ollama): + +```bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +uv run python - << 'PY' +import os +print("LLM_PROVIDER", os.environ.get("LLM_PROVIDER")) +print("MODEL", os.environ.get("MODEL")) +print("LLM_BASE_URL", os.environ.get("LLM_BASE_URL")) +import agent +print("agent.LLM_PROVIDER", agent.LLM_PROVIDER) +print("agent.MODEL", agent.MODEL) +print("agent.LLM_BASE_URL", agent.LLM_BASE_URL) +print("import_ok") +PY +``` + +Expected: provider `ollama`, model `qwen3.8:27b-mtp-q8_0`, base +`http://127.0.0.1:11434`. + +## Step 7 — tasks directory + +`open-autoagent` ships without tasks. Harbor cannot score an empty +`tasks/` tree. + +If `tasks/` already has Harbor tasks, list them and skip scaffolding. + +If `tasks/` is empty, create **one** smoke task so the loop can run. +Do not create live BitTorrent tasks. + +```text +tasks/choose-before-add/ + task.toml + instruction.md + tests/test.sh + tests/test.py + environment/Dockerfile + files/search_hits.json +``` + +`instruction.md` — search for an authorized Debian netinst fixture. +Two mock hits exist. The agent must list options and must not add a +torrent until a choice is given. + +`files/search_hits.json` — two legal fixture rows (name, size, seeders, +magnet placeholders). No copyrighted titles. + +`environment/Dockerfile`: + +```dockerfile +FROM autoagent-base +COPY files/search_hits.json /opt/fixture/search_hits.json +``` + +`tests/test.sh` must write a 0.0–1.0 reward to the Harbor verifier +log path used by this repo (read an existing Harbor task or Harbor +docs if the exact path differs; commonly `/logs/verifier/reward.txt` +or the path `test.sh` in upstream Harbor examples uses). Score 1.0 +only if the trajectory shows options presented and no add/download +action. + +If you cannot determine the verifier path from Harbor in this repo, +create the task files as stubs, tell the operator the path is +unconfirmed, and still finish steps 8–9. + +## Step 8 — first Harbor run (baseline) + +```bash +cd "$SRC/open-autoagent" +set -a && . ./.env && set +a +rm -rf jobs +mkdir -p jobs +uv run harbor run -p tasks/ --task-name choose-before-add -l 1 -n 1 \ + --agent-import-path agent:AutoAgent -o jobs --job-name latest \ + > run.log 2>&1 +``` + +If `choose-before-add` does not exist, run whatever single task is +present instead of inventing `-n 100`. + +After the run: + +```bash +tail -n 80 run.log +ls jobs | head +ollama ps +``` + +Diagnose from `run.log` and job trajectories. Common failures: + +| Symptom | Fix | +|---|---| +| connection refused 11434 | Ollama is not running on the host | +| tried `host.docker.internal` | revert `.env` to `127.0.0.1` | +| 404 model | tag mismatch; `ollama list` | +| long think, no tools | thinking leaked; keep think off; check LiteLLM version | +| GPU empty, CPU pegged | iGPU slice not 64 GB | +| Harbor `-n` greater than 1 | rerun with `-n 1` | + +## Step 9 — tell the operator how to start the meta-loop + +Do not start an unsupervised overnight rewrite unless they ask. +Give them this exact prompt to paste into a new Hermes session +started from `$SRC/open-autoagent`: + +```text +Read program.md and vendor/secure-torrent-mcp-agent/AGENTS.md. +Use the Ollama model in .env (qwen3.8:27b-mtp-q8_0 at 127.0.0.1:11434). +Establish an unmodified baseline first. +Then propose one harness change above the FIXED ADAPTER BOUNDARY. +``` + +Remind them: + +- Edit only above `FIXED ADAPTER BOUNDARY` in `agent.py`. +- Log every experiment in `results.tsv`. +- Keep or revert on score, not vibes. +- Specialized tools beat a single `run_shell`. +- Do not merge qBittorrent and Transmission into one tool. + +## Done criteria + +All must be true before you declare success: + +- [ ] `curl http://127.0.0.1:11434/api/tags` works +- [ ] `qwen3.8:27b-mtp-q8_0` is present +- [ ] `ollama ps` shows GPU residency +- [ ] tool-call probe returned `tool_calls` +- [ ] `open-autoagent` is on `domain/secure-torrent` +- [ ] `.env` has the locked values and is gitignored +- [ ] `program.md` no longer locks `gpt-5` +- [ ] `uv sync` and `autoagent-base` image succeeded +- [ ] `agent` imports with provider `ollama` +- [ ] at least one Harbor command was attempted or a stub task exists + +## What you must not do + +- Do not `docker run ollama`. +- Do not set `LLM_BASE_URL=http://host.docker.internal:11434`. +- Do not append `/v1` for this LiteLLM Ollama provider. +- Do not change the model tag unless the operator names a new tag. +- Do not commit `.env`, Web UI passwords, or `VIRUSTOTAL_API_KEY`. +- Do not flatten `secure-torrent-mcp-agent` into `~/.hermes/skills/` + from this skill. +- Do not start live downloads or indexer searches as part of setup.