> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection. CLI-Anything generates a full agent-ready CLI harness for any software in one command. It analyzes source code or repos, designs a Click-based CLI with structured JSON output, implements REPL interaction, writes comprehensive tests, and publishes to PATH — bridging AI agents and the world's software through the universal CLI interface. ---
Scanned 9/8/2026
Install to Claude Code
npx -y skills add Aradotso/trending-skills --skill cli-anything-agent-native --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Cli Anything Agent Native?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/aradotso-cli-anything-agent-native)More formats (shields.io, HTML) on the badges page.
```markdown
---
name: cli-anything-agent-native
description: Make any software agent-controllable by generating a complete CLI harness with JSON output, REPL, tests, and docs in one command
triggers:
- make this software agent-native
- generate a CLI harness for this app
- use cli-anything to wrap this software
- build an agent-ready CLI for this project
- cli-anything build harness
- make this tool work with AI agents
- wrap this application with a CLI using cli-anything
- use cli-anything to expose this software to agents
---
# CLI-Anything: Making ALL Software Agent-Native
> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.
CLI-Anything generates a full agent-ready CLI harness for any software in one command. It analyzes source code or repos, designs a Click-based CLI with structured JSON output, implements REPL interaction, writes comprehensive tests, and publishes to PATH — bridging AI agents and the world's software through the universal CLI interface.
---
## What CLI-Anything Does
Given any software (local path or GitHub repo), CLI-Anything runs a **7-phase pipeline**:
1. 🔍 **Analyze** — Scans source, maps GUI actions to APIs
2. 📐 **Design** — Architects command groups, state model, output formats
3. 🔨 **Implement** — Builds Click CLI with REPL, JSON output, undo/redo
4. 📋 **Plan Tests** — Creates `TEST.md` with unit + E2E test plans
5. 🧪 **Write Tests** — Implements comprehensive test suite
6. 📝 **Document** — Updates `TEST.md` with results
7. 📦 **Publish** — Creates `setup.py`, installs to PATH
The output lives in `<software>/agent-harness/` and is immediately usable by any AI agent.
---
## Installation
### Prerequisites
- Python 3.10+
- Target software installed (GIMP, Blender, LibreOffice, or any app)
- A supported AI coding agent (Claude Code, OpenCode, OpenClaw, Codex, Qodercli)
### Claude Code (Recommended)
```bash
# Add the CLI-Anything marketplace
/plugin marketplace add HKUDS/CLI-Anything
# Install the plugin
/plugin install cli-anything
```
> **Windows users:** Claude Code uses `bash`. Install Git for Windows (includes `bash` + `cygpath`) or use WSL to avoid `cygpath: command not found` errors.
### Manual Installation (Claude Code)
```bash
git clone https://github.com/HKUDS/CLI-Anything.git
cp -r CLI-Anything/cli-anything-plugin ~/.claude/plugins/cli-anything
/reload-plugins
```
### OpenCode
```bash
git clone https://github.com/HKUDS/CLI-Anything.git
# Global install
cp CLI-Anything/opencode-commands/*.md ~/.config/opencode/commands/
cp CLI-Anything/cli-anything-plugin/HARNESS.md ~/.config/opencode/commands/
# Or project-level
cp CLI-Anything/opencode-commands/*.md .opencode/commands/
cp CLI-Anything/cli-anything-plugin/HARNESS.md .opencode/commands/
```
### OpenClaw
```bash
git clone https://github.com/HKUDS/CLI-Anything.git
mkdir -p ~/.openclaw/skills/cli-anything
cp CLI-Anything/openclaw-skill/SKILL.md ~/.openclaw/skills/cli-anything/SKILL.md
```
Then invoke: `@cli-anything build a CLI for ./gimp`
### Codex
```bash
git clone https://github.com/HKUDS/CLI-Anything.git
bash CLI-Anything/codex-skill/scripts/install.sh
# Windows: .\CLI-Anything\codex-skill\scripts\install.ps1
```
### Qodercli
```bash
git clone https://github.com/HKUDS/CLI-Anything.git
bash CLI-Anything/qoder-plugin/setup-qodercli.sh
```
---
## Core Commands
### Building a Harness
```bash
# Claude Code — generate full CLI for a local app
/cli-anything:cli-anything ./gimp
# Claude Code — generate from a GitHub repo
/cli-anything:cli-anything https://github.com/blender/blender
# OpenCode
/cli-anything ./gimp
/cli-anything https://github.com/blender/blender
# Codex (natural language)
# "Use CLI-Anything to build a harness for ./gimp"
```
> **Claude Code < 2.x:** Use `/cli-anything` instead of `/cli-anything:cli-anything`.
### Refining an Existing Harness
```bash
# Broad refinement — agent analyzes all gaps
/cli-anything:refine ./gimp
# Focused refinement — target a specific area
/cli-anything:refine ./gimp "image batch processing and filters"
# OpenCode equivalents
/cli-anything-refine ./gimp
/cli-anything-refine ./gimp "batch processing and filters"
# Codex
# "Use CLI-Anything to refine ./shotcut for picture-in-picture workflows"
```
Refine is **incremental and non-destructive** — run it multiple times to expand coverage.
### Validation & Testing
```bash
# OpenCode: validate the generated harness
/cli-anything-validate ./gimp
# OpenCode: run tests
/cli-anything-test ./gimp
# Codex
# "Use CLI-Anything to validate ./libreoffice"
```
### Listing Available Harnesses
```bash
# OpenCode
/cli-anything-list
```
---
## Using a Generated CLI
After the pipeline completes, the harness is in `<software>/agent-harness/`.
### Install to PATH
```bash
cd gimp/agent-harness
pip install -e .
```
### Basic Usage
```bash
# Get help (self-documenting for agents)
cli-anything-gimp --help
cli-anything-gimp layer --help
# Create a new project
cli-anything-gimp project new --width 1920 --height 1080 -o poster.json
# Add a layer (JSON output mode)
cli-anything-gimp --json layer add -n "Background" --type solid --color "#1a1a2e"
# Open a file
cli-anything-gimp file open ./image.png
# Export
cli-anything-gimp file export --format png --output ./out.png
```
### JSON Output Mode
Every command supports `--json` for structured agent consumption:
```bash
cli-anything-gimp --json project new --width 800 --height 600
```
```json
{
"status": "ok",
"command": "project new",
"result": {
"width": 800,
"height": 600,
"layers": [],
"id": "proj_abc123"
}
}
```
On error:
```json
{
"status": "error",
"command": "layer add",
"error": "No active project. Run `project new` or `file open` first.",
"code": "NO_ACTIVE_PROJECT"
}
```
### Interactive REPL
```bash
# Enter REPL (stateful session)
cli-anything-gimp
# Inside REPL:
# > project new --width 1920 --height 1080
# > layer add -n "Sky" --type gradient
# > layer add -n "Text" --type text --content "Hello"
# > undo
# > redo
# > file export --format jpeg --quality 90
# > exit
```
### Undo / Redo
```bash
cli-anything-gimp undo
cli-anything-gimp redo
cli-anything-gimp history --last 10
```
---
## Generated Harness Structure
```
gimp/
└── agent-harness/
├── setup.py # pip-installable package
├── TEST.md # Test plan + results
├── cli_anything_gimp/
│ ├── __init__.py
│ ├── main.py # Click CLI entrypoint
│ ├── commands/
│ │ ├── project.py # project new/open/save/close
│ │ ├── layer.py # layer add/remove/reorder/merge
│ │ ├── filter.py # filter apply/list/preview
│ │ ├── file.py # file open/export/import
│ │ └── ...
│ ├── state.py # Application state model
│ ├── output.py # JSON + human output formatting
│ └── repl.py # Interactive REPL
└── tests/
├── unit/
│ ├── test_project.py
│ ├── test_layer.py
│ └── ...
└── e2e/
├── test_workflow_poster.py
└── ...
```
---
## Writing a Custom Harness (Python Pattern)
If you need to manually create or extend a harness, here's the standard pattern CLI-Anything follows:
### Entry Point (`main.py`)
```python
import click
import json
import sys
from .state import AppState
from .output import output_result, output_error
from .commands import project, layer, file_ops, filters
@click.group()
@click.option("--json", "json_mode", is_flag=True, default=False,
help="Output results as JSON for agent consumption")
@click.pass_context
def cli(ctx, json_mode):
"""CLI-Anything harness for GIMP — agent-ready interface."""
ctx.ensure_object(dict)
ctx.obj["json_mode"] = json_mode
ctx.obj["state"] = AppState()
cli.add_command(project.group)
cli.add_command(layer.group)
cli.add_command(file_ops.group)
cli.add_command(filters.group)
if __name__ == "__main__":
cli()
```
### Command Group (`commands/layer.py`)
```python
import click
from ..output import output_result, output_error
@click.group(name="layer")
def group():
"""Manage image layers."""
pass
@group.command("add")
@click.option("-n", "--name", required=True, help="Layer name")
@click.option("--type", "layer_type",
type=click.Choice(["solid", "gradient", "text", "image"]),
default="solid")
@click.option("--color", default="#ffffff", help="Fill color (hex)")
@click.pass_context
def add(ctx, name, layer_type, color):
"""Add a new layer to the active project."""
state = ctx.obj["state"]
json_mode = ctx.obj["json_mode"]
if not state.active_project:
output_error(ctx, "NO_ACTIVE_PROJECT",
"No active project. Run `project new` or `file open` first.")
return
try:
layer = state.active_project.add_layer(name, layer_type, color)
output_result(ctx, {
"layer_id": layer.id,
"name": layer.name,
"type": layer.type,
"index": layer.index,
}, message=f"Added layer '{name}'")
except Exception as e:
output_error(ctx, "LAYER_ADD_FAILED", str(e))
```
### Output Formatter (`output.py`)
```python
import click
import json
import sys
def output_result(ctx, data: dict, message: str = ""):
json_mode = ctx.obj.get("json_mode", False)
if json_mode:
click.echo(json.dumps({"status": "ok", "result": data}, indent=2))
else:
if message:
click.echo(f"✓ {message}")
for key, val in data.items():
click.echo(f" {key}: {val}")
def output_error(ctx, code: str, message: str):
json_mode = ctx.obj.get("json_mode", False)
if json_mode:
click.echo(json.dumps({
"status": "error",
"code": code,
"error": message
}, indent=2))
else:
click.echo(f"✗ Error [{code}]: {message}", err=True)
sys.exit(1)
```
### State Model (`state.py`)
```python
from dataclasses import dataclass, field
from typing import Optional, List
import uuid
@dataclass
class Layer:
id: str = field(default_factory=lambda: f"layer_{uuid.uuid4().hex[:8]}")
name: str = ""
type: str = "solid"
color: str = "#ffffff"
index: int = 0
visible: bool = True
@dataclass
class Project:
id: str = field(default_factory=lambda: f"proj_{uuid.uuid4().hex[:8]}")
width: int = 1920
height: int = 1080
layers: List[Layer] = field(default_factory=list)
_history: List[dict] = field(default_factory=list)
def add_layer(self, name: str, layer_type: str, color: str) -> Layer:
layer = Layer(name=name, type=layer_type, color=color,
index=len(self.layers))
self._history.append({"action": "add_layer", "layer": layer})
self.layers.append(layer)
return layer
def undo(self):
if not self._history:
raise ValueError("Nothing to undo")
last = self._history.pop()
if last["action"] == "add_layer":
self.layers.remove(last["layer"])
@dataclass
class AppState:
active_project: Optional[Project] = None
def new_project(self, width: int, height: int) -> Project:
self.active_project = Project(width=width, height=height)
return self.active_project
```
### `setup.py`
```python
from setuptools import setup, find_packages
setup(
name="cli-anything-gimp",
version="0.1.0",
packages=find_packages(),
install_requires=["click>=8.0"],
entry_points={
"console_scripts": [
"cli-anything-gimp=cli_anything_gimp.main:cli",
],
},
)
```
---
## Testing the Generated Harness
```bash
# Run all tests
cd gimp/agent-harness
pytest tests/ -v
# Run only unit tests
pytest tests/unit/ -v
# Run E2E workflow tests
pytest tests/e2e/ -v
# With coverage
pytest tests/ --cov=cli_anything_gimp --cov-report=term-missing
```
### Example Unit Test
```python
# tests/unit/test_layer.py
from click.testing import CliRunner
from cli_anything_gimp.main import cli
import json
def test_add_layer_json_output():
runner = CliRunner()
# First create a project
result = runner.invoke(cli, ["--json", "project", "new",
"--width", "800", "--height", "600"])
assert result.exit_code == 0
result = runner.invoke(cli, ["--json", "layer", "add",
"-n", "Background", "--type", "solid",
"--color", "#ff0000"])
assert result.exit_code == 0
data = json.loads(result.output)
assert data["status"] == "ok"
assert data["result"]["name"] == "Background"
def test_add_layer_no_project_returns_error():
runner = CliRunner()
result = runner.invoke(cli, ["--json", "layer", "add", "-n", "Test"])
data = json.loads(result.output)
assert data["status"] == "error"
assert data["code"] == "NO_ACTIVE_PROJECT"
```
### Example E2E Test
```python
# tests/e2e/test_workflow_poster.py
from click.testing import CliRunner
from cli_anything_gimp.main import cli
import json
def test_full_poster_workflow():
runner = CliRunner()
# 1. New project
r = runner.invoke(cli, ["--json", "project", "new",
"--width", "1920", "--height", "1080"])
assert json.loads(r.output)["status"] == "ok"
# 2. Add background
r = runner.invoke(cli, ["--json", "layer", "add",
"-n", "Background", "--color", "#1a1a2e"])
assert json.loads(r.output)["status"] == "ok"
# 3. Add text layer
r = runner.invoke(cli, ["--json", "layer", "add",
"-n", "Title", "--type", "text"])
assert json.loads(r.output)["status"] == "ok"
# 4. Export
r = runner.invoke(cli, ["--json", "file", "export",
"--format", "png", "--output", "/tmp/poster.png"])
assert json.loads(r.output)["status"] == "ok"
```
---
## Supported Applications (Built-in Demos)
CLI-Anything has been demonstrated and tested against 11 apps:
| App | Harness Name | Key Command Groups |
|-----|-------------|-------------------|
| GIMP | `cli-anything-gimp` | project, layer, filter, file |
| Blender | `cli-anything-blender` | scene, object, render, animation |
| LibreOffice | `cli-anything-libreoffice` | document, spreadsheet, presentation |
| Shotcut | `cli-anything-shotcut` | project, timeline, clip, export |
| Zoom | `cli-anything-zoom` | meeting, audio, video, participants |
| + 6 more | — | — |
---
## Common Patterns for AI Agents
### Chain Commands via JSON
```bash
# Agent workflow: create → edit → export
cli-anything-gimp --json project new --width 1200 --height 800 | \
jq -r '.result.id' | \
xargs -I{} cli-anything-gimp --json layer add -n "BG" --color "#000"
cli-anything-gimp --json file export --format png --output result.png
```
### Check Status Before Acting
```python
import subprocess, json
def run_cli(cmd: list[str]) -> dict:
result = subprocess.run(
["cli-anything-gimp", "--json"] + cmd,
capture_output=True, text=True
)
return json.loads(result.stdout)
state = run_cli(["project", "status"])
if state["status"] == "ok" and state["result"]["has_active_project"]:
run_cli(["layer", "add", "-n", "Overlay", "--type", "solid"])
else:
run_cli(["project", "new", "--width", "1920", "--height", "1080"])
```
### Discover Available Commands
```bash
# Agents can always self-discover via --help
cli-anything-gimp --help
cli-anything-gimp layer --help
cli-anything-gimp filter --help
```
---
## Troubleshooting
### `cygpath: command not found` (Windows)
Claude Code runs via `bash`. Install **Git for Windows** (includes bash + cygpath) or use **WSL**.
### `command not found: cli-anything-gimp`
```bash
# Ensure the harness is installed
cd gimp/agent-harness && pip install -e .
# Verify entry point
pip show cli-anything-gimp
which cli-anything-gimp
```
### `No active project` errors
The generated CLI is **stateful within a session**. In scripts, always run `project new` or `file open` before other commands:
```bash
cli-anything-gimp project new --width 1920 --height 1080
cli-anything-gimp layer add -n "Layer 1"
```
### Plugin not found after install (Claude Code)
```bash
/reload-plugins
# Verify with:
/plugin list
```
### OpenCode: HARNESS.md not found
`HARNESS.md` must be in the **same directory** as the command `.md` files:
```bash
cp CLI-Anything/cli-anything-plugin/HARNESS.md ~/.config/opencode/commands/
```
### Tests failing after refine
The refine command adds new commands but existing tests are non-destructive. If tests break, run:
```bash
cd gimp/agent-harness
/cli-anything:refine ./gimp # re-run to fix gaps
pytest tests/ -v
```
### LibreOffice / GIMP path issues on Windows/macOS
Check that the application binary is on your `$PATH` or use absolute paths when invoking the harness's underlying API. The generated `state.py` typically includes a `BINARY_PATH` config you can override:
```python
# In cli_anything_libreoffice/state.py
BINARY_PATH = "/Applications/LibreOffice.app/Contents/MacOS/soffice"
```
---
## Key Design Principles
| Principle | Implementation |
|-----------|---------------|
| **Structured output** | Every command supports `--json` flag |
| **Self-describing** | Full `--help` on all commands and groups |
| **Stateful REPL** | `AppState` persists across REPL commands |
| **Undo/redo** | History stack in state model |
| **Agent-first errors** | Errors include `code` + `message` in JSON |
| **Composable** | Commands chain via pipes and scripting |
| **Deterministic** | Same inputs → same outputs, no side effects |
```
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!