Skip to main content

Run any command with retry, timeout, and JSON extraction for AI agents

Project description

exec-json

Run any command with retry, timeout, and JSON extraction for AI agents

AI-Ready Zero Dependencies Python 3.8+

For LLMs: Executes a shell command with exponential backoff, extracts a valid JSON from mixed output, validates it against an optional schema, and returns a structured diagnostic report – all in a single deterministic CLI tool.


Installation

pip install exec-json

Or install from source:

git clone https://github.com/your-org/exec-json.git
cd exec-json
pip install -e .

Usage

CLI reference

Argument Type Default Description
--cmd str required Command to execute (wrap in quotes).
--retries int 3 Maximum number of retry attempts.
--timeout float 30.0 Per-attempt timeout in seconds.
--backoff float 2.0 Exponential backoff factor: wait = backoff^attempt.
--schema str None Path to a .json schema file or inline JSON string for validation.
--shell flag False Use shell=True in subprocess (enables pipes, redirects, etc.).
--no-extract flag False Skip JSON extraction; return raw stdout only.
--version Print version and exit.

Input → Output examples

Input Output (compressed)
--cmd "echo '{\"status\":\"ok\"}'" {"success": true, "exit_code": 0, "parsed_json": {"status": "ok"}, ...}
--cmd "invalid-command" {"success": false, "error": "Command not found: invalid-command", ...}
--cmd "" {"success": false, "error": "No command provided", ...}
--cmd "sleep 10" --timeout 0.5 {"success": false, "error": "Command timed out after 0.5s", ...}

Examples

Before/After — Recovering from a flaky command

Before: A command that fails 50% of the time requires custom retry logic.

# Manual retry loop – fragile, no structured output
for i in 1 2 3; do
  output=$(flaky-command 2>/dev/null) && break
  sleep $((2**i))
done
echo "$output"

After: exec-json handles retry, backoff, and structured output automatically.

exec-json --cmd "flaky-command" --retries 3 --backoff 2.0
{
  "success": true,
  "attempts": 2,
  "duration_ms": 1502.3,
  "parsed_json": { "result": "data" }
}

Before/After — Extracting JSON from verbose log output

Before: Grep + sed + jq – brittle and verbose.

output=$(some-tool --verbose 2>&1)
json=$(echo "$output" | grep -oP '\{.*\}' | head -1)
echo "$json" | jq .

After: A single exec-json call with automatic extraction.

exec-json --cmd "some-tool --verbose"
{
  "success": true,
  "parsed_json": { "metric": 42, "unit": "ms" },
  "stdout_raw": "[2024-01-01] Starting...\n{\"metric\": 42, \"unit\": \"ms\"}\nDone.\n"
}

Before/After — Schema validation

Before: Manual validation with ad‑hoc checks.

output=$(produce-json)
echo "$output" | python -c "
import json, sys
data = json.load(sys.stdin)
assert 'id' in data, 'missing id'
assert isinstance(data['id'], int), 'id not int'
"

After: Declarative schema validation built in.

exec-json --cmd "produce-json" --schema '{"type":"object","required":["id"],"properties":{"id":{"type":"integer"}}}'
{
  "success": true,
  "parsed_json": { "id": 1, "name": "test" },
  "schema_valid": true,
  "schema_errors": []
}

Error handling

Scenario error suggestion
Empty command No command provided Pass a command with --cmd
Timeout Command timed out after Xs Increase --timeout or simplify the command
Command not found Command not found: <cmd> Verify the command is installed and in PATH
Schema file missing Schema file not found Verify path
Invalid schema JSON Invalid JSON schema: ... Check schema syntax
Non-zero exit code Command exited with code X Review the command output for errors

Note: exec-json always exits with code 0. The agent reads the JSON to decide how to proceed, avoiding cascade failures in chained tool calls.


Output schema

Every invocation returns a JSON object with the following structure:

Field Type Description
success bool true if the last attempt had exit code 0.
exit_code int Last exit code (or -1 for timeout).
attempts int Total attempts made.
duration_ms float Wall-clock duration in milliseconds.
stdout_raw str Full stdout from the final/last attempt.
stderr_raw str Full stderr from the final/last attempt.
parsed_json any Extracted JSON value, or null.
schema_valid bool or null true/false if schema provided, null otherwise.
schema_errors list[str] Validation error messages (empty on success).
error str (only if success == false) Error description.
suggestion str (only if success == false) Actionable suggestion.

MCP Integration

exec-json ships with a built-in MCP server that exposes the CLI as a native MCP tool named run_command, ready for use with Claude Desktop, Cline, Cursor, and any MCP-compatible agent.

The server communicates exclusively via stdio (standard input/output) — no HTTP or cloud services are involved.

Quick start

After installing the package, the MCP server is available as the exec-json-mcp command:

exec-json-mcp

Or directly with Python:

python -m server

Exposed tool: run_command

Parameter Type Default Description
cmd str required Command to execute.
retries int 3 Maximum retry attempts.
timeout float 30.0 Per-attempt timeout in seconds.
backoff float 2.0 Exponential backoff factor.
schema str None JSON schema file path or inline string.
shell bool False Use shell=True.
no_extract bool False Skip JSON extraction.

The tool returns the same structured JSON output as the CLI (see Output schema).

Claude Desktop configuration

Add the following entry to your claude_desktop_config.json:

Windows: %APPDATA%\Claude\claude_desktop_config.json

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

Linux: ~/.config/Claude/claude_desktop_config.json

{
  "mcpServers": {
    "exec-json": {
      "command": "exec-json-mcp"
    }
  }
}

If the command is not in your PATH, use the full Python invocation:

{
  "mcpServers": {
    "exec-json": {
      "command": "python",
      "args": ["-m", "server"]
    }
  }
}

Verifying the server

To test that the server starts correctly, run:

exec-json-mcp

The server will listen on stdio and wait for MCP requests. No output means it started successfully. You can also run the provided integration test:

python -m unittest tests.test_mcp_server -v

Why AI Agents Choose This

  • 🔬 Deterministic — Same input always produces the same structured JSON. No ambiguity, no parsing guesswork.
  • 📦 Predictable output — Rigid JSON schema means agents can programmatically extract parsed_json, schema_valid, and error without custom parsing.
  • 🔄 Automatic retry — Exponential backoff handles transient failures (network hiccups, rate limits, service restarts) without custom loop logic.
  • 🛠 Robust JSON extraction — Finds valid JSON even when embedded in log noise, error messages, or multi-line text — no more brittle grep or sed pipelines.

License

MIT — see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

exec_json-1.0.0.tar.gz (21.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

exec_json-1.0.0-py3-none-any.whl (15.1 kB view details)

Uploaded Python 3

File details

Details for the file exec_json-1.0.0.tar.gz.

File metadata

  • Download URL: exec_json-1.0.0.tar.gz
  • Upload date:
  • Size: 21.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for exec_json-1.0.0.tar.gz
Algorithm Hash digest
SHA256 77fe1dc15b18b71c4246908fd98f3989e5b950af9178dd85d6eca247cafba80c
MD5 0b30f5b42a7bcceb3a0023b3216f86fc
BLAKE2b-256 4f87d998592fa4dcc660dc6fc28e83aba3dcc1aa7ff2cb3a886a0d87bcd18dea

See more details on using hashes here.

File details

Details for the file exec_json-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: exec_json-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 15.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for exec_json-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bbd6483ee908b8e025fdd527c8d68cc147c838994b07bc688c45570b5e09b714
MD5 5f7c2909acc903fbb269f5fe2b0dbdd3
BLAKE2b-256 850fbec7758952b3c00b4bd59ebee26445c7404dbfcb00e2eab31e91a496ff68

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page