diff --git a/.plugin/marketplace.json b/.plugin/marketplace.json index 14acf5a..71e6f94 100644 --- a/.plugin/marketplace.json +++ b/.plugin/marketplace.json @@ -226,6 +226,19 @@ "cloud-native" ] }, + { + "name": "adapt-yourself", + "source": "./adapt-yourself", + "description": "Decide how to make OpenHands adapt/improve itself persistently: skills, AGENTS.md, hooks, plugins, MCP servers, or code changes in OpenHands-CLI and software-agent-sdk.", + "category": "development", + "keywords": [ + "openhands", + "customization", + "skills", + "hooks", + "plugins" + ] + }, { "name": "notion", "source": "./notion", diff --git a/skills/adapt-yourself/README.md b/skills/adapt-yourself/README.md new file mode 100644 index 0000000..3996930 --- /dev/null +++ b/skills/adapt-yourself/README.md @@ -0,0 +1,8 @@ +# adapt-yourself + +This skill is a playbook for “self-modification” requests: + +- deciding whether the user actually needs code changes, vs. +- adding a repo/user skill, always-on repo instructions (`AGENTS.md`), hooks (`.openhands/hooks.json`), plugins, or MCP tooling. + +The canonical instructions live in [`SKILL.md`](SKILL.md). diff --git a/skills/adapt-yourself/SKILL.md b/skills/adapt-yourself/SKILL.md new file mode 100644 index 0000000..0d6a2b3 --- /dev/null +++ b/skills/adapt-yourself/SKILL.md @@ -0,0 +1,152 @@ +--- +name: adapt-yourself +description: Decide how to make OpenHands adapt/improve itself persistently (after restart) by choosing between repo/user skills, always-on instructions, hooks, plugins, MCP servers, or code changes in OpenHands-CLI and software-agent-sdk. Includes uv + uv tool workflows and restart/reload behavior. +triggers: +- modify yourself +- change your behavior +- self-modify +- adapt yourself +- self modification +- hack openhands +- .agents/skills +- hooks.json +- plugin.json +--- + +# Modify OpenHands (self-modification playbook) + +When a user says things like “modify yourself to do X” or “remember this next time”, **don’t jump to editing Python code**. +OpenHands has multiple extensibility layers; choose the *smallest*, *safest*, and *most persistent* mechanism that matches the user’s intent. + +This skill is about **persistent** changes that should still apply after the user reloads or restarts the CLI / app. If the user wants behavior only for the current conversation, you don't need the mechanisms in this skill—just follow their instructions directly in this session. + +## 0) First: clarify what kind of change the user wants + +Clarify the **scope** and **type** of the change (skip questions the user already answered): + +1. **Persistence scope**: Should this change apply… + - for this *repository/workspace*? + - for *all repos on this machine* (user-global)? + - for *everyone* (contribution upstream / extensions registry)? +2. **Change type**: Is it primarily… + - instructions/workflow (“when I ask for X, do Y”)? + - a safety/policy constraint (“never run rm -rf”, “ask before network calls”)? + - a new capability/tool integration (GitHub, Jira, internal APIs, etc.)? + - a bug fix / UI change in the CLI or SDK? +3. **Where do they run OpenHands?** + - `uv tool install openhands` (tool environment) + - from a local clone (developer workflow) + - via a remote runtime / server + +Then follow the decision tree below. + +## 1) Prefer non-code extensibility (often enough) + +### 1.1 Write a skill (AgentSkills / progressive disclosure) + +Use when the user wants repeatable expertise/workflows, e.g.: +- “When I say ‘release notes’, use this structure” +- “Here’s how we do migrations in our company” +- “Read the Daytona docs and learn how to use it” + +**Where to put it (in priority order):** + +1. **Project-local (recommended):** `/.agents/skills//SKILL.md` +2. **User-global:** `~/.agents/skills//SKILL.md` + +Notes: +- **Project skills override user + public skills** (same `name`). This is the simplest way to “patch” a public skill locally. +- Add `triggers:` only when you really want automatic activation; prefer **distinctive phrases** to avoid injecting the skill on unrelated messages. + +See: [Templates](references/TEMPLATES.md#agentskillsskillmd-template). + +### 1.2 Add always-on repo instructions (AGENTS.md) + +Use when the user wants **always-applied** guidance for a repository (style, commands, guardrails, conventions): + +- Create or edit `/AGENTS.md` (or model-specific variants like `CLAUDE.md`, `GEMINI.md` if your environment supports them). +- Put the repo rules there. + +This gets loaded at conversation start as “always-on context” (not progressive disclosure). + +### 1.3 Add hooks (policy/automation) via `.openhands/hooks.json` + +Use when the user wants **enforcement** or **automation** around tool usage, e.g.: +- “Before any git commit, run tests.” +- “Block any command that tries to access prod without approval.” +- “Reject tool calls that write outside the repo.” + +Hooks are executed on lifecycle events (like `pre_tool_use`) and can **allow / block / modify** actions. + +See: [Hook templates](references/TEMPLATES.md#hookshooksjson-template) and [Hook architecture notes](references/ARCHITECTURE.md#hooks). + +### 1.4 Add tools via MCP (`.mcp.json`) + +Recommend MCP **only when there is a concrete MCP server to add**: + +- The user explicitly asks to “add an MCP server”, **or** +- The user asks for a capability and you can point to an existing MCP server for it (e.g., from that project’s docs / an official MCP server repo). + +If there isn’t an MCP server available for what they want, don’t force MCP: +- start with a **skill** (instructions/workflow), or +- if they truly need a new tool, the real work item is to **build or install an MCP server** (or implement a native tool/code change). + +MCP server configuration location **depends on the runtime**: + +- **OpenHands-CLI** persists MCP servers in `~/.openhands/mcp.json` (or `$OPENHANDS_PERSISTENCE_DIR/mcp.json`). +- **Software Agent SDK skills/plugins** use a **per-skill/per-plugin** `.mcp.json` file located inside the skill/plugin directory. + +See: [MCP template](references/TEMPLATES.md#mcp-template). + +### 1.5 Package it as a plugin (shareable bundle) + +Use when the change should be **portable** across repos or shared with others, and it includes more than just instructions: +- skills + hooks + MCP config together +- optional slash commands and/or specialized agents + +Plugins follow the Claude Code-compatible structure, with `.plugin/plugin.json` (or `.claude-plugin/plugin.json`). + +See: [Plugin template](references/TEMPLATES.md#plugin-template) and [Plugin architecture notes](references/ARCHITECTURE.md#plugins). + +## 2) When code changes are actually required + +Choose the correct codebase / package: + +- **CLI UX, TUI widgets, slash commands, config files** → `OpenHands/OpenHands-CLI` +- **Agent runtime logic, skill loading, hooks system, plugin loader, event model** → `OpenHands/software-agent-sdk` → `openhands-sdk` +- **Built-in tools (Terminal, File Editor, Task Tracker, etc.)** → `OpenHands/software-agent-sdk` → `openhands-tools` +- **Workspace mounting / file sync / workspace abstraction** → `OpenHands/software-agent-sdk` → `openhands-workspace` + +If you’re not sure, start by reproducing the issue and locating the code path. + +## 3) uv development workflows (including `uv tool install openhands`) + +- If they run OpenHands from a **local clone**: use `uv sync` + `uv run openhands`. +- If they installed OpenHands via **`uv tool install openhands`**: + - safest: `uv tool run --from /path/to/OpenHands-CLI openhands` + - persistent: `uv tool install --force --editable /path/to/OpenHands-CLI` +- If they need to modify the **SDK** while running the CLI, remember: the CLI often **pins exact SDK/tool versions**. Prefer aligning versions; use overrides only for local development. + +Details: [Installation modes (`uv tool` vs `uv run`)](references/INSTALLATION_MODES.md). + +## 4) What requires a restart to take effect? + +- **Skills / AGENTS.md**: loaded at conversation start → usually **start a new conversation** to pick them up. Ask the user to fully restart OpenHands only if needed. +- **Hooks (.openhands/hooks.json)**: loaded when the agent/conversation initializes → ask the user to restart (or create a fresh session) to guarantee reload. +- **Plugins**: loaded when the conversation initializes → ask the user to restart (or create a fresh session) to guarantee reload. +- **Editable Python code (uv tool `--editable` or local `uv run`)**: changes apply the next time the Python process starts → ask the user to restart the CLI/app. + +## 5) Verification checklist + +After making a “self-modification” change, guide the **user** through verification: + +1. Ask the user to start a **fresh conversation** (and restart OpenHands only if needed). +2. If they’re using the **OpenHands CLI TUI**, ask them to type `/skills` to confirm the expected skills/hooks/MCPs are loaded. +3. Ask the user to send a tiny, deterministic **test prompt** that should trigger the new behavior. +4. If it’s a code change, run the smallest relevant test suite (or ask the user to run it) and confirm the behavior matches. + +## References + +- [Architecture: CLI vs SDK vs skills/hooks/plugins](references/ARCHITECTURE.md) +- [Installation modes: `uv tool` vs `uv run` and version pinning](references/INSTALLATION_MODES.md) +- [Templates: SKILL.md, hooks.json, plugin.json, .mcp.json](references/TEMPLATES.md) diff --git a/skills/adapt-yourself/references/ARCHITECTURE.md b/skills/adapt-yourself/references/ARCHITECTURE.md new file mode 100644 index 0000000..1dc140b --- /dev/null +++ b/skills/adapt-yourself/references/ARCHITECTURE.md @@ -0,0 +1,101 @@ +# OpenHands extensibility architecture (CLI + SDK) + +OpenHands “behavior” can be modified at multiple layers. The key is to choose the layer that matches the user’s intent. + +## Components + +### OpenHands CLI (`OpenHands/OpenHands-CLI`) + +- Python package name: `openhands` +- Entry points: `openhands`, `openhands-acp` +- Responsibilities: + - Terminal UI (Textual) + - Loading config + wiring up an SDK `Agent` + - Choosing tools and building an `AgentContext` + +In the CLI codebase, look for where it creates the `AgentContext` and enables: +- project skills +- user skills +- public skills + +### Software Agent SDK monorepo (`OpenHands/software-agent-sdk`) + +This repo is a **uv workspace** that produces multiple packages: + +- `openhands-sdk` (module: `openhands.sdk`) + - agent runtime primitives (Agent, Conversation, Event model) + - context loading (skills) + - hooks system + - plugin loader + +- `openhands-tools` (module: `openhands.tools`) + - built-in tools used by many OpenHands projects + +- `openhands-workspace` (module: `openhands.workspace`) + - workspace mounting, file sync abstractions + +- `openhands-agent-server` + - server-side runtime + +## Skills + +Skills are loaded from multiple locations; **project-local skills override user + public**. + +Common locations: + +- Project-local: + - `/.agents/skills/` + +- User-global: + - `~/.agents/skills/` + +- Public registry: + - `https://github.com/OpenHands/extensions` (cached locally under `~/.openhands/skills-cache/`) + +Skill types: + +- **AgentSkills format**: a directory with `SKILL.md` (progressive disclosure) +- **Always-on instructions**: repo instruction files like `AGENTS.md` (loaded at conversation start) + +## Hooks + +Hooks are configured via JSON and executed on events (e.g. `pre_tool_use`). + +Typical locations (depending on project / SDK config): + +- `/.openhands/hooks.json` +- `~/.openhands/hooks.json` + +Hook scripts receive an event payload on stdin as JSON and respond with a decision. + +## Plugins + +Plugins are bundles of: + +- skills +- hooks +- MCP config +- optional commands and agents + +They follow the Claude Code-compatible directory structure: + +``` +my-plugin/ +├── .plugin/ +│ └── plugin.json +├── skills/ +├── hooks/ +│ └── hooks.json +├── .mcp.json +└── README.md +``` + +Plugins can be: +- loaded from a local path +- fetched from GitHub/git URLs and cached under `~/.openhands/cache/plugins/` + +## MCP servers (tools) + +MCP servers provide tool endpoints to the agent. + +They are configured via `.mcp.json` (location depends on host project). Plugins can also provide MCP config. diff --git a/skills/adapt-yourself/references/INSTALLATION_MODES.md b/skills/adapt-yourself/references/INSTALLATION_MODES.md new file mode 100644 index 0000000..18b965b --- /dev/null +++ b/skills/adapt-yourself/references/INSTALLATION_MODES.md @@ -0,0 +1,114 @@ +# Installation and development modes (uv) + +This reference is for making “persistent self-modifications” that apply after restart. + +## `uv run` (project environment) mode + +Use when you are developing from a git clone. + +- `uv sync` installs dependencies into a project-local `.venv/` (and/or uses the uv lockfile). +- `uv run ...` runs inside that environment. + +Typical CLI dev flow: + +```bash +cd OpenHands-CLI +uv sync --group dev +uv run openhands +``` + +Typical SDK dev flow: + +```bash +cd software-agent-sdk +uv sync --group dev +uv run pytest +``` + +### Pros + +- Simple debugging (local sources) +- Easy to run tests + linters +- No global tool replacement needed + +### Cons + +- You must run `openhands` via `uv run openhands` (or ensure the venv is on PATH) + +## `uv tool install openhands` (tool environment) mode + +In this mode, `uv` installs the CLI into a dedicated tool environment and exposes a shim executable. + +### Inspect installed tools + +```bash +uv tool list +uv tool dir +``` + +If `openhands` is installed and not found on PATH, run: + +```bash +uv tool update-shell +``` + +### Replace the tool with an editable local checkout + +This is the most common way to run a modified CLI *after restart*: + +```bash +uv tool install --force --editable /path/to/OpenHands-CLI +``` + +After that, `openhands` should use the editable sources. + +### Run a local checkout without installing + +This is the safest way to test a change: + +```bash +uv tool run --from /path/to/OpenHands-CLI openhands +``` + +## SDK vs CLI version pins + +The CLI often pins exact versions of: + +- `openhands-sdk` +- `openhands-tools` +- `openhands-workspace` + +If you want to use a local SDK checkout *together with the CLI*, you must handle that pinning. + +### What usually works + +1. Check the versions the CLI requires: + - `OpenHands-CLI/pyproject.toml` +2. Check out the matching tag/commit in `software-agent-sdk`. +3. Install the matching SDK packages in editable mode into the environment that runs the CLI. + +### What commonly fails + +Trying to install an SDK checkout at version `X` into an environment where the CLI requires `openhands-sdk==Y`. + +### Using `--overrides` for development + +As a last resort for local development, you can override pinned deps. + +Create a file (e.g. `overrides.txt`) containing a direct URL or local path spec: + +```text +openhands-sdk @ file:///absolute/path/to/software-agent-sdk/openhands-sdk +openhands-tools @ file:///absolute/path/to/software-agent-sdk/openhands-tools +openhands-workspace @ file:///absolute/path/to/software-agent-sdk/openhands-workspace +``` + +Then install the CLI tool using that overrides file: + +```bash +uv tool install --force --editable /path/to/OpenHands-CLI --overrides overrides.txt +``` + +Notes: +- This is intentionally “break glass”; it can produce a mismatched runtime. +- Prefer aligning versions whenever possible. diff --git a/skills/adapt-yourself/references/TEMPLATES.md b/skills/adapt-yourself/references/TEMPLATES.md new file mode 100644 index 0000000..0937d65 --- /dev/null +++ b/skills/adapt-yourself/references/TEMPLATES.md @@ -0,0 +1,156 @@ +# Templates + +Use these as starting points when implementing a “self-modification” without changing OpenHands code. + +## AgentSkills (`SKILL.md`) template + +If you decide an Agentskill is appropriate for user's request to remember or adapt to their needs, you can create it. First, create a directory: + +``` +/.agents/skills// +└── SKILL.md +``` + +Example `SKILL.md`: + +```md +--- +name: my-team-workflow +description: Our team’s workflow for X. Use when the user asks about X. +triggers: +- team x workflow +- how do we do x +--- + +# Our workflow for X + +## When to use + +Use this workflow when... + +## Steps + +1. ... +2. ... + +## Verification + +- Run: `...` +``` + +Notes: +- Keep triggers distinctive. +- Keep the file focused; put deep details in `references/`. + +## Always-on repo instructions (`AGENTS.md`) template + +Create `/AGENTS.md`: + +```md +# Project rules + +## Build / run +- `make install` +- `make test` + +## Code style +- Ruff formatting + +## Safety +- Never run destructive commands without asking +``` + +## Hooks (`.openhands/hooks.json`) template + +If you decide a Hook is appropriate for addressing the user's request to adapt for next time, you can create a hook. Create or use `/.openhands/hooks.json`: + +```json +{ + "pre_tool_use": [ + { + "command": "bash .openhands/hooks/block-dangerous.sh", + "matchers": { + "tool_name": "terminal" + } + } + ] +} +``` + +Then create the script `/.openhands/hooks/block-dangerous.sh`: + +```bash +#!/usr/bin/env bash + +# stdin: HookEvent JSON +payload="$(cat)" + +# Example: block `rm -rf ...` for Terminal tool calls. +# Requires: jq +cmd="$(echo "$payload" | jq -r '.tool_input.command // ""')" + +if echo "$cmd" | grep -Eq '(^|[[:space:]])rm[[:space:]]+-rf([[:space:]]|$)'; then + # HookExecutor parses JSON on stdout; "decision" must be "allow" or "deny". + jq -n --arg reason "Blocked destructive command" '{"decision":"deny","reason":$reason}' + exit 0 +fi + +jq -n '{"decision":"allow"}' +``` + +Notes: +- Prefer parsing the structured fields (like `.tool_input.command`) rather than grepping raw JSON. +- The exact `tool_input` shape is tool-specific; inspect the SDK `HookEvent` schema and your tool inputs. + +## Plugin template + +Plugin structure: + +``` +my-plugin/ +├── .plugin/ +│ └── plugin.json +├── skills/ +│ └── my-skill/ +│ └── SKILL.md +├── hooks/ +│ └── hooks.json +├── .mcp.json +└── README.md +``` + +Minimal `.plugin/plugin.json` (fields vary by plugin schema): + +```json +{ + "name": "my-plugin", + "version": "0.1.0", + "description": "My custom OpenHands behavior", + "author": { + "name": "Example", + "email": "dev@example.com" + } +} +``` + +## MCP template (`.mcp.json`) + +Minimal example: + +```json +{ + "mcpServers": { + "my-server": { + "command": "python", + "args": ["-m", "my_mcp_server"], + "env": { + "MY_SERVER_TOKEN": "$MY_SERVER_TOKEN" + } + } + } +} +``` + +Notes: +- Never hardcode real secrets in files. +- Prefer environment variables.