diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..3a19bef --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @anwhelan01 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..08accc4 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,18 @@ +name: ci + +on: + push: + branches: [main] + pull_request: + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Syntax + run: | + python -m compileall -q . diff --git a/.hermes/SOUL.md b/.hermes/SOUL.md new file mode 100644 index 0000000..f6b3b65 --- /dev/null +++ b/.hermes/SOUL.md @@ -0,0 +1,5 @@ +# CLI + +You are the k3ss CLI front door. You wrap Hermes. You do not invent a second agent stack. + +If a specialist Bot exists for the job, tell the operator to `gpt-cli -p chat` or `@mention` them in Bot Mode. diff --git a/.hermes/bot.yaml b/.hermes/bot.yaml new file mode 100644 index 0000000..d03ab72 --- /dev/null +++ b/.hermes/bot.yaml @@ -0,0 +1,14 @@ +name: cli +title: CLI +description: Thin Hermes front door. Use this when the operator types gpt-cli. +avatar: + silhouette: boxy + color: zinc +soul: SOUL.md +skills: [] +toolsets: + - terminal +groups: + - desks +agent: + bot_mode_protocol: true diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..826d4dd --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,14 @@ +# AGENTS.md — gpt_cli + +This repo used to be scratch space for GPT-class CLI loops. It is now a **thin front door to Hermes Agent**. + +Do not reintroduce a hand-rolled agent loop. Route through `hermes -p `. + +```bash +pip install -e . +gpt-cli chat +HERMES_PROFILE=rae gpt-cli chat +gpt-cli -p cordon chat +``` + +Hard rules: no secrets in git; prefer the specialist Bot over improvising. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7c49ac0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Tony Whelan (anwhelan01) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 5831ff7..bf582a3 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,47 @@ +
+ # gpt_cli -CLI experiments with GPT-class models — agent loops, tooling, prompt harnesses. +**The old GPT experiments now ride the Hermes harness.** + +

+ Hermes Bot Mode + Python + MIT +

+ +Thin front door to [Hermes Agent](https://hermes-agent.nousresearch.com/). Same hands, better harness. + +
+ +## Why this exists + +Hand-rolled GPT agent loops rot. Hermes already has memory, skills, cron, and **Bot Mode** (named Bots with their own soul, routines, and `@mentions`). This package is a 40-line exec into that. + +## Install + +```bash +# Hermes itself +curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash + +# this wrapper +pip install -e . +./scripts/install-hermes-bot.sh +``` + +## Use + +```bash +gpt-cli # hermes -p cli chat +gpt-cli -p rae chat # orchestrator +gpt-cli -p cordon chat # OSINT desk +HERMES_PROFILE=walk-in gpt-cli +``` -Scratch space for whatever the current obsession is. Expect small tools, not frameworks. +`gcli` is an alias for `gpt-cli`. ## Related -- [kess_projects](https://github.com/anwhelan01/kess_projects) — hosted AI/python projects +- [k3ss-memory](https://github.com/anwhelan01/k3ss-memory) — ledger + fleet roster (private) +- [kess_projects](https://github.com/anwhelan01/kess_projects) — private project index +- [Hermes Bot Mode](https://hermes-agent.nousresearch.com/docs/user-guide/bot-mode) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..be21cff --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,6 @@ +# Security + +- Do not commit API keys, cookies, or session tokens. +- `XAI_API_KEY` and provider secrets stay in the environment, never in git. +- Report vulnerabilities privately: open a security advisory on this repo, or email the owner via GitHub. +- This project is operated by [anwhelan01](https://github.com/anwhelan01). diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..ef911f0 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,20 @@ +[project] +name = "gpt-cli" +version = "0.2.0" +description = "Thin front door to Hermes Agent. The old GPT experiments now ride the Hermes harness." +readme = "README.md" +requires-python = ">=3.10" +license = { text = "MIT" } +authors = [{ name = "Tony Whelan" }] +dependencies = [] + +[project.scripts] +gpt-cli = "gpt_cli.__main__:main" +gcli = "gpt_cli.__main__:main" + +[build-system] +requires = ["setuptools>=68"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.packages.find] +where = ["src"] diff --git a/scripts/install-hermes-bot.sh b/scripts/install-hermes-bot.sh new file mode 100755 index 0000000..b4245be --- /dev/null +++ b/scripts/install-hermes-bot.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# Install this repo as a Hermes Bot Mode profile. +# Docs: https://hermes-agent.nousresearch.com/docs/user-guide/bot-mode +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +YAML="$ROOT/.hermes/bot.yaml" +SOUL="$ROOT/.hermes/SOUL.md" + +if [[ ! -f "$YAML" ]]; then + echo "missing $YAML" >&2 + exit 1 +fi + +NAME="$(awk '/^name:/{print $2; exit}' "$YAML" | tr -d '"' | tr -d "'")" +HERMES_HOME="${HERMES_HOME:-$HOME/.hermes}" +DEST="$HERMES_HOME/profiles/$NAME" + +mkdir -p "$DEST/skills" "$DEST/memories" +cp "$YAML" "$DEST/bot.yaml" +if [[ -f "$SOUL" ]]; then + cp "$SOUL" "$DEST/SOUL.md" +fi +if [[ -d "$ROOT/.hermes/skills" ]]; then + cp -R "$ROOT/.hermes/skills/." "$DEST/skills/" +fi +if [[ -f "$ROOT/.hermes/routines.yaml" ]]; then + cp "$ROOT/.hermes/routines.yaml" "$DEST/routines.yaml" +fi + +# Project-local skills are also discovered at /.hermes/skills when cwd is the repo. +echo "Installed Hermes bot '$NAME'" +echo " profile: $DEST" +echo " chat: hermes -p $NAME chat" +echo " cron: hermes cron list # namespaced [bot:$NAME]" +echo +echo "Desktop: Bots tab → the profile is on this machine. @${NAME} from any chat." +if [[ ! -x "$(command -v hermes || true)" ]]; then + echo + echo "Hermes CLI not on PATH. Install:" + echo " curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash" +fi diff --git a/src/gpt_cli/__init__.py b/src/gpt_cli/__init__.py new file mode 100644 index 0000000..d3ec452 --- /dev/null +++ b/src/gpt_cli/__init__.py @@ -0,0 +1 @@ +__version__ = "0.2.0" diff --git a/src/gpt_cli/__main__.py b/src/gpt_cli/__main__.py new file mode 100644 index 0000000..2be4b02 --- /dev/null +++ b/src/gpt_cli/__main__.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +"""gpt_cli — thin front door to Hermes Agent (Bot Mode aware).""" +from __future__ import annotations + +import os +import shutil +import subprocess +import sys + +INSTALL = "curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash" + + +def main(argv: list[str] | None = None) -> int: + argv = list(sys.argv[1:] if argv is None else argv) + hermes = shutil.which("hermes") + if hermes is None: + sys.stderr.write( + "Hermes Agent is not on PATH.\n" + f"Install it, then retry:\n {INSTALL}\n" + ) + return 127 + profile = os.environ.get("HERMES_PROFILE", "cli") + if argv and argv[0] in {"-p", "--profile"} and len(argv) >= 2: + profile = argv[1] + argv = argv[2:] + if not argv: + argv = ["chat"] + cmd = [hermes, "-p", profile, *argv] + return subprocess.call(cmd) + + +if __name__ == "__main__": + raise SystemExit(main())