From 026466610a95f7d23986f2c95a35f1f1559a3b24 Mon Sep 17 00:00:00 2001 From: Abiorh001 Date: Mon, 30 Mar 2026 11:35:58 +0100 Subject: [PATCH 1/2] fix dependency issue and skills.md --- .agents/skills/omniclaw-cli/SKILL.md | 159 +++++++++++++++++++++++---- pyproject.toml | 1 + src/omniclaw/__init__.py | 2 +- src/omniclaw/agent/routes.py | 2 +- src/omniclaw/cli.py | 47 +++++--- src/omniclaw/cli_agent.py | 49 +++++++-- uv.lock | 2 + 7 files changed, 218 insertions(+), 44 deletions(-) diff --git a/.agents/skills/omniclaw-cli/SKILL.md b/.agents/skills/omniclaw-cli/SKILL.md index ab25ce9..b7fefc7 100644 --- a/.agents/skills/omniclaw-cli/SKILL.md +++ b/.agents/skills/omniclaw-cli/SKILL.md @@ -14,31 +14,57 @@ requires: Scoped agent token tied to your wallet. Set by the owner before your session starts. Never print, log, or transmit this value. If it is missing, stop and notify the owner — you cannot proceed without it. -version: 1.0.0 +version: 0.0.2 author: Omnuron AI --- # OmniClaw Agent Skill -## What this skill does +## Installation -OmniClaw is the financial control plane your owner configured before your -session. It lets you: +Install the CLI: -- Pay for HTTP services that return 402 Payment Required (x402 protocol) -- Transfer USDC directly to a wallet address -- Expose your own service behind a payment gate so other agents can pay you -- Check your available balance and transaction history +```bash +pip install omniclaw +``` -It does not let you change your own spending limits, add recipients to -whitelists, approve pending payments, or touch any wallet configuration. -Those are owner-only. If you need any of those, stop and notify the owner. +Verify installation: + +```bash +omniclaw-cli --version +# or +omniclaw-cli ping +``` + +--- + +## Configuration (one-time setup) + +Before using any payment commands, you must configure the CLI with your server details: + +```bash +omniclaw-cli configure \ + --server-url \ + --token \ + --wallet +``` + +**Where to get these values:** +- `--server-url`: Your OmniClaw server URL (e.g., `https://api.omniclaw.com` or `http://localhost:8080`) +- `--token`: Your scoped agent token (from your owner) +- `--wallet`: Your wallet alias (e.g., `primary`) + +**Verify configuration:** + +```bash +omniclaw-cli configure --show +``` --- -## Before you do anything +## Verify Setup -**Check your environment is ready:** +Before making any payments, always verify your environment is ready: ```bash omniclaw-cli status @@ -47,17 +73,30 @@ omniclaw-cli status Expected output: ``` Agent: -Wallet: wlt_xxxxx +Wallet: 0x... Balance: $X.XX available Guards: active -Network: Arc Testnet -Circle: connected ✓ -Circuit: CLOSED ✓ +Circle: connected ✅ +Circuit: CLOSED ✅ ``` -If `Circuit: OPEN` or `Circle: disconnected`, wait 30 seconds and run -`omniclaw-cli status` again before attempting any payment. If it stays degraded, -notify the owner. +If `Circuit: OPEN` or `Circle: disconnected`, wait 30 seconds and run `omniclaw-cli status` again. If it stays degraded, stop and notify the owner. + +--- + +## What this skill does + +OmniClaw is the financial control plane your owner configured before your +session. It lets you: + +- Pay for HTTP services that return 402 Payment Required (x402 protocol) +- Transfer USDC directly to a wallet address +- Expose your own service behind a payment gate so other agents can pay you +- Check your available balance and transaction history + +It does not let you change your own spending limits, add recipients to +whitelists, approve pending payments, or touch any wallet configuration. +Those are owner-only. If you need any of those, stop and notify the owner. --- @@ -182,6 +221,64 @@ before you can pay. --- +## Payment Intents (authorize now, capture later) + +For payments you want to authorize first and capture later: + +**Create a payment intent (authorize):** +```bash +omniclaw-cli create-intent \ + --recipient 0x742d35Cc6634C0532925a3b844Bc9e7595f5e4a0 \ + --amount 1.00 \ + --purpose "reserved-compute-job" +``` + +**Confirm (capture) the intent:** +```bash +omniclaw-cli confirm-intent --intent-id +``` + +**Get intent status:** +```bash +omniclaw-cli get-intent --intent-id +``` + +**Cancel an intent:** +```bash +omniclaw-cli cancel-intent --intent-id --reason "no longer needed" +``` + +--- + +## Network and Fee Options + +**Specify destination chain:** +```bash +omniclaw-cli pay --recipient
--destination-chain ethereum +``` + +**Set gas fee level:** +```bash +omniclaw-cli pay --recipient
--fee-level HIGH +``` +Options: LOW, MEDIUM, HIGH + +**Run Trust Gate check:** +```bash +omniclaw-cli pay --recipient
--check-trust +``` + +--- + +## Simulate (standalone) + +Use `--dry-run` on `pay` or the standalone `simulate` command: +```bash +omniclaw-cli simulate --recipient 0x742d35Cc6634C0532925a3b844Bc9e7595f5e4a0 --amount 0.50 +``` + +--- + ## How to view your transactions ```bash @@ -269,12 +366,21 @@ omniclaw-cli status # Check available balance omniclaw-cli balance +# Get your wallet address +omniclaw-cli address + +# Health check +omniclaw-cli ping + # Check if you can pay a recipient omniclaw-cli can-pay --recipient # Simulate a payment (no charge) omniclaw-cli pay --recipient --dry-run +# Standalone simulation +omniclaw-cli simulate --recipient
--amount + # Pay an x402 URL (handles 402 automatically) omniclaw-cli pay --recipient --idempotency-key @@ -294,6 +400,19 @@ omniclaw-cli pay --recipient <0xAddress> \ --purpose \ --idempotency-key +# Pay with specific chain/fee +omniclaw-cli pay --recipient
--destination-chain ethereum --fee-level HIGH + +# Payment Intents +omniclaw-cli create-intent --recipient --amount --purpose +omniclaw-cli confirm-intent --intent-id +omniclaw-cli get-intent --intent-id +omniclaw-cli cancel-intent --intent-id + # View transactions omniclaw-cli ledger + +# Configure (first time only) +omniclaw-cli configure --server-url --token --wallet +omniclaw-cli configure --show ``` diff --git a/pyproject.toml b/pyproject.toml index f157a29..0756d53 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,6 +61,7 @@ dependencies = [ "typer>=0.15.0", "fastapi>=0.100.0", "uvicorn[standard]>=0.20.0", + "setuptools>=69.0.0", ] [project.optional-dependencies] diff --git a/src/omniclaw/__init__.py b/src/omniclaw/__init__.py index 65b9d2c..ad04a31 100644 --- a/src/omniclaw/__init__.py +++ b/src/omniclaw/__init__.py @@ -147,7 +147,7 @@ ) from omniclaw.trust.gate import TrustGate -__version__ = "0.1.0" +__version__ = "0.0.2" __all__ = [ # Main Client "OmniClaw", diff --git a/src/omniclaw/agent/routes.py b/src/omniclaw/agent/routes.py index a087013..5d9f0d3 100644 --- a/src/omniclaw/agent/routes.py +++ b/src/omniclaw/agent/routes.py @@ -66,7 +66,7 @@ async def get_current_agent( @router.get("/health", response_model=HealthResponse) async def health_check(): - return HealthResponse(status="healthy") + return HealthResponse(status="ok") @router.get("/address", response_model=AddressResponse) diff --git a/src/omniclaw/cli.py b/src/omniclaw/cli.py index 98751f4..6a19005 100644 --- a/src/omniclaw/cli.py +++ b/src/omniclaw/cli.py @@ -13,6 +13,24 @@ from omniclaw.onboarding import print_doctor_status +BANNER = r""" + ____ __ __ _ _ ___ ____ _ ___ __ + / __ \| \/ | \ | |_ _/ ___| | / \ \ / / + | | | | |\/| | \| || | | | | / _ \ \ /\ / / + | |__| | | | | |\ || | |___| |___ / ___ \ V V / + \____/|_| |_|_| \_|___\____|_____/_/ \_\_/\_/ + + OmniClaw is the economy and control layer for AI agent payments. + Economic Execution and Control Layer for Agentic Systems +""" + + +def print_banner(): + """Print the OmniClaw CLI banner.""" + print(f"\033[1;36m{BANNER}\033[0m") + print("\033[90mOmniClaw Financial Infrastructure - v2.0 Production-Ready\033[0m\n") + + ENV_VARS = { "required": { "CIRCLE_API_KEY": "Circle API key for wallet/payment operations", @@ -40,7 +58,7 @@ def print_env_vars(): print("Required:") for var, desc in ENV_VARS["required"].items(): value = os.environ.get(var, "") - status = f"✓ {value[:20]}..." if value else "✗ not set" + status = f"✓ {value[:20]}..." if value else "✗ not set" print(f" {var}") print(f" {desc}") print(f" {status}\n") @@ -48,7 +66,7 @@ def print_env_vars(): print("\nOptional:") for var, desc in ENV_VARS["optional"].items(): value = os.environ.get(var, "") - status = f"✓ {value[:30]}..." if value else "○ default" + status = f"✓ {value[:30]}..." if value else "○ default" print(f" {var}") print(f" {desc}") print(f" {status}\n") @@ -56,7 +74,7 @@ def print_env_vars(): print("\nProduction:") for var, desc in ENV_VARS["production"].items(): value = os.environ.get(var, "") - status = f"✓ {value[:30]}..." if value else "○ not set" + status = f"✓ {value[:30]}..." if value else "○ not set" print(f" {var}") print(f" {desc}") print(f" {status}\n") @@ -116,21 +134,21 @@ def handle_setup(args: argparse.Namespace) -> int: api_key = input("Enter your Circle API Key: ").strip() if not api_key: - print("❌ Error: Circle API Key is required.") + print("❌ Error: Circle API Key is required.") return 1 entity_secret = resolve_entity_secret(api_key) if entity_secret: - print("✅ Found existing Entity Secret in managed store.") + print("✅ Found existing Entity Secret in managed store.") else: - print("💡 No Entity Secret found for this API key.") + print("💡 No Entity Secret found for this API key.") entity_secret = input( "Enter your 64-char Entity Secret (or press Enter to generate): " ).strip() if not entity_secret: from omniclaw.onboarding import auto_setup_entity_secret - print("🚀 Generating and registering new Entity Secret...") + print("🚀 Generating and registering new Entity Secret...") entity_secret = auto_setup_entity_secret(api_key) env_path = ".env.agent" @@ -150,30 +168,30 @@ def handle_server(args: argparse.Namespace) -> int: # Load .env.agent if it exists if os.path.exists(".env.agent"): load_dotenv(".env.agent") - print("📝 Loaded configuration from .env.agent") + print("📄 Loaded configuration from .env.agent") elif os.path.exists(".env"): load_dotenv(".env") - print("📝 Loaded configuration from .env") + print("📄 Loaded configuration from .env") # Auto-Setup Logic: Check if we have an API key but no Entity Secret api_key = os.getenv("CIRCLE_API_KEY") entity_secret = os.getenv("ENTITY_SECRET") if api_key and not entity_secret: - print("💡 Found API Key but no Entity Secret. Attempting auto-setup...") + print("💡 Found API Key but no Entity Secret. Attempting auto-setup...") entity_secret = resolve_entity_secret(api_key) if not entity_secret: - print("🚀 Generating new Entity Secret for this machine...") + print("🚀 Generating new Entity Secret for this machine...") entity_secret = auto_setup_entity_secret(api_key) if entity_secret: os.environ["ENTITY_SECRET"] = entity_secret - print("✅ Credentials verified and injected.") + print("✅ Credentials verified and injected.") else: - print("❌ Error: Failed to resolve or generate Entity Secret.") + print("❌ Error: Failed to resolve or generate Entity Secret.") return 1 - print(f"🚀 Starting OmniClaw Control Plane on {args.host}:{args.port}...") + print(f"🚀 Starting OmniClaw Control Plane on {args.host}:{args.port}...") uvicorn.run( "omniclaw.agent.server:app", host=args.host, @@ -188,6 +206,7 @@ def main(argv: Sequence[str] | None = None) -> int: """Run the OmniClaw CLI.""" parser = build_parser() args = parser.parse_args(argv) + print_banner() if args.command == "doctor": print_doctor_status( diff --git a/src/omniclaw/cli_agent.py b/src/omniclaw/cli_agent.py index 93f84a0..12afcde 100644 --- a/src/omniclaw/cli_agent.py +++ b/src/omniclaw/cli_agent.py @@ -18,11 +18,35 @@ import httpx import typer -app = typer.Typer(help="omniclaw-cli - CLI for AI agents to make USDC payments") +app = typer.Typer( + help="omniclaw-cli - CLI for AI agents to pay for things without losing control of money" +) + + +@app.callback() +def callback() -> None: + """Show banner on startup.""" + print_banner() + CONFIG_DIR = Path.home() / ".omniclaw" CONFIG_FILE = CONFIG_DIR / "config.json" +BANNER = r""" + ____ __ __ _ _ ___ ____ _ ___ __ + / __ \| \/ | \ | |_ _/ ___| | / \ \ / / + | | | | |\/| | \| || | | | | / _ \ \ /\ / / + | |__| | | | | |\ || | |___| |___ / ___ \ V V / + \____/|_| |_|_| \_|___\____|_____/_/ \_\_/\_/ + + Economic Execution and Control Layer for Agentic Systems +""" + + +def print_banner(): + """Print the OmniClaw CLI banner.""" + typer.echo(typer.style(BANNER, fg=typer.colors.CYAN, bold=True)) + def load_config() -> dict[str, Any]: """Load configuration from file.""" @@ -58,9 +82,9 @@ def get_client() -> httpx.Client: @app.command() def configure( - server_url: str = typer.Option(..., "--server-url", help="OmniClaw server URL"), - token: str = typer.Option(..., "--token", help="Agent token"), - wallet: str = typer.Option(..., "--wallet", help="Wallet alias"), + server_url: str | None = typer.Option(None, "--server-url", help="OmniClaw server URL"), + token: str | None = typer.Option(None, "--token", help="Agent token"), + wallet: str | None = typer.Option(None, "--wallet", help="Wallet alias"), show: bool = typer.Option(False, "--show", help="Show current config"), ) -> None: """Configure omniclaw-cli with server details.""" @@ -72,6 +96,10 @@ def configure( typer.echo(json.dumps(config, indent=2)) return + if not server_url or not token or not wallet: + typer.echo("Error: --server-url, --token, and --wallet are required", err=True) + raise typer.Exit(1) + config = { "server_url": server_url.rstrip("/"), "token": token, @@ -164,7 +192,7 @@ def pay( # If recipient is a URL, handle x402 flow if recipient.startswith("http"): - typer.echo(f"🚀 Paying for x402 service: {recipient}") + typer.echo(f"🚀 Paying for x402 service: {recipient}") payload: dict[str, Any] = { "url": recipient, "method": method, @@ -182,7 +210,7 @@ def pay( data = response.json() if output: Path(output).write_text(json.dumps(data, indent=2)) - typer.echo(f"✅ Response saved to {output}") + typer.echo(f"✅ Response saved to {output}") else: typer.echo(json.dumps(data, indent=2)) return data @@ -548,8 +576,10 @@ def status() -> dict[str, Any]: typer.echo(f"Wallet: {status_data['Wallet']}") typer.echo(f"Balance: {status_data['Balance']}") typer.echo(f"Guards: {status_data['Guards']}") - typer.echo(f"Circle: {status_data['Circle']} ✓") - typer.echo(f"Circuit: {status_data['Circuit']} ✓") + circle_icon = "✅" if status_data["Circle"] == "connected" else "❌" + circuit_icon = "✅" if status_data["Circuit"] == "CLOSED" else "⚠️" + typer.echo(f"Circle: {status_data['Circle']} {circle_icon}") + typer.echo(f"Circuit: {status_data['Circuit']} {circuit_icon}") return status_data except Exception as e: @@ -560,12 +590,15 @@ def status() -> dict[str, Any]: @app.command() def ping() -> dict[str, Any]: """Health check.""" + from omniclaw import __version__ + client = get_client() try: response = client.get("/api/v1/health") response.raise_for_status() data = response.json() + data["version"] = __version__ typer.echo(json.dumps(data, indent=2)) return data except httpx.HTTPStatusError as e: diff --git a/uv.lock b/uv.lock index c2902cc..2c68d92 100644 --- a/uv.lock +++ b/uv.lock @@ -2099,6 +2099,7 @@ dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, { name = "redis" }, + { name = "setuptools" }, { name = "tenacity" }, { name = "typer" }, { name = "uvicorn", extra = ["standard"] }, @@ -2145,6 +2146,7 @@ requires-dist = [ { name = "python-dotenv", specifier = ">=1.2.1" }, { name = "redis", specifier = "==7.1.0" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.14.0" }, + { name = "setuptools", specifier = ">=69.0.0" }, { name = "tenacity", specifier = "==8.2.0" }, { name = "twine", marker = "extra == 'dev'", specifier = ">=6.1.0" }, { name = "typer", specifier = ">=0.15.0" }, From dc0c06551a0efbcbbc293a491d6966718e8babdb Mon Sep 17 00:00:00 2001 From: Abiorh001 Date: Mon, 30 Mar 2026 11:42:30 +0100 Subject: [PATCH 2/2] fix ruff --- src/omniclaw/cli.py | 6 +++--- src/omniclaw/cli_agent.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/omniclaw/cli.py b/src/omniclaw/cli.py index 6a19005..d36a08b 100644 --- a/src/omniclaw/cli.py +++ b/src/omniclaw/cli.py @@ -16,9 +16,9 @@ BANNER = r""" ____ __ __ _ _ ___ ____ _ ___ __ / __ \| \/ | \ | |_ _/ ___| | / \ \ / / - | | | | |\/| | \| || | | | | / _ \ \ /\ / / - | |__| | | | | |\ || | |___| |___ / ___ \ V V / - \____/|_| |_|_| \_|___\____|_____/_/ \_\_/\_/ + | | | | |\/| | \| || | | | | / _ \ \ /\ / / + | |__| | | | | |\ || | |___| |___ / ___ \ V V / + \____/|_| |_|_| \_|___\____|_____/_/ \_\_/\_/ OmniClaw is the economy and control layer for AI agent payments. Economic Execution and Control Layer for Agentic Systems diff --git a/src/omniclaw/cli_agent.py b/src/omniclaw/cli_agent.py index 12afcde..1770bfb 100644 --- a/src/omniclaw/cli_agent.py +++ b/src/omniclaw/cli_agent.py @@ -35,9 +35,9 @@ def callback() -> None: BANNER = r""" ____ __ __ _ _ ___ ____ _ ___ __ / __ \| \/ | \ | |_ _/ ___| | / \ \ / / - | | | | |\/| | \| || | | | | / _ \ \ /\ / / - | |__| | | | | |\ || | |___| |___ / ___ \ V V / - \____/|_| |_|_| \_|___\____|_____/_/ \_\_/\_/ + | | | | |\/| | \| || | | | | / _ \ \ /\ / / + | |__| | | | | |\ || | |___| |___ / ___ \ V V / + \____/|_| |_|_| \_|___\____|_____/_/ \_\_/\_/ Economic Execution and Control Layer for Agentic Systems """