agent-cli
Add agent-friendly --json NDJSON output to Python CLI scripts, or scaffold a complete cli_utils package for a project. Use this skill when the user wants to make scripts machine-readable for AI agents, add --json flags, convert print statements to structured JSON, build a CLI helper library, create an open-source CLI-for-agents package, add structured logging, or make CLI output machine-readable. Also use when the user mentions NDJSON, structured CLI output, agent-friendly CLI, non-interactive scripts, or JSON I/O for automation.
What this skill does
# Agent-Friendly CLI Builder
Convert Python CLI scripts from human-only output to agent-consumable NDJSON, or scaffold a complete `cli_utils` package ready for open-source distribution.
## Two Modes
### Mode A: Convert an existing script
When the user points at a script and says "make this agent-friendly" or "add --json":
1. **Scan** the script for output points
2. **Generate** `cli_utils.py` if the project doesn't have one
3. **Replace** all output with structured helpers
4. **Verify** no raw output leaks in JSON mode
### Mode B: Scaffold a complete package
When the user says "create a cli_utils package" or wants an open-source library:
1. **Scaffold** a full Python package with pyproject.toml, tests, license, README
2. **Include** all helpers: `json_log`, `json_error`, `die`, `log`, `add_json_flag`, `enable_json`, `is_json`
3. **Add** pytest test suite with full coverage
4. **Add** MIT license (or ask user preference)
## Core Architecture
The fundamental pattern: every script gets a `--json` flag. When active, **all stdout becomes newline-delimited JSON** (NDJSON). Each line is a self-contained JSON object with a standard envelope.
### The NDJSON Event Envelope
Every JSON line has at minimum:
```json
{"event": "ready", "ts": "2026-04-30T14:00:00+00:00", "pid": 1234, "port": 8765}
```
- `event` — what happened (snake_case string)
- `ts` — ISO 8601 UTC timestamp
- Additional fields are event-specific kwargs
### Why This Design
- **NDJSON over JSON arrays**: processable line-by-line, one bad line doesn't break the stream, works with grep/jq, low memory for long-running processes
- **`--json` opt-in over default**: preserves human DX, doesn't break existing scripts or habits
- **Global mode flag over per-call checks**: set once at startup, every helper respects it automatically
- **`die()` over repeated if/else**: the pattern `if is_json(): json_error(); sys.exit(1) else: print(); sys.exit()` appears constantly — `die()` collapses it to one line
## The cli_utils.py Reference Implementation
When generating `cli_utils.py`, produce exactly this (adapt only if the project has specific needs):
```python
"""Shared helpers for JSON CLI output."""
import json
import os
import sys
from datetime import datetime, timezone
_json_mode = False
def enable_json():
global _json_mode
_json_mode = True
def is_json():
return _json_mode
def json_log(event: str, **kwargs):
"""Emit one NDJSON line to stdout."""
obj = {"event": event, "ts": datetime.now(timezone.utc).isoformat(), **kwargs}
print(json.dumps(obj, default=str), flush=True)
def json_error(message: str, **kwargs):
"""Emit a structured error event."""
json_log("error", message=message, **kwargs)
def die(message: str, code: int = 1, **kwargs):
"""Print error and exit — JSON or human depending on mode."""
if _json_mode:
json_error(message, **kwargs)
else:
print(message, file=sys.stderr)
sys.exit(code)
def add_json_flag(parser):
"""Add --json flag to an argparse parser."""
parser.add_argument("--json", action="store_true",
help="NDJSON output for agent consumption")
def log(message: str, **json_kwargs):
"""Print human message normally, or emit JSON event if --json is active."""
if _json_mode:
json_log(json_kwargs.pop("event", "info"), message=message, **json_kwargs)
else:
print(message)
def json_ready(**kwargs):
"""Emit the readiness signal — only in JSON mode. Call early in daemon startup."""
if _json_mode:
json_log("ready", pid=os.getpid(), **kwargs)
```
## Converting a Script — Step by Step
### Step 1: Scan for output points
Search the target script for all places that produce output or exit:
```bash
grep -n 'print(\|sys\.exit\|exit(\|input(\|os\.system.*say' TARGET.py
```
Categorize each hit:
- **Informational print** → replace with `log(message, event="descriptive_name")`
- **Error + exit** → replace with `die(message)`
- **Status line with \r** → replace with `if is_json(): json_log("status", ...) else: print("\r...", end="", flush=True)`
- **Interactive input()** → guard with `if not is_json():` or add `--no-interactive` flag
- **Side effects (say, osascript, notifications)** → guard with `if not is_json():`
- **Import-time errors** (before argparse runs) → use `sys.exit("message")` (writes to stderr)
### Step 2: Add the import and flag
At the top of the script, after existing imports:
```python
from cli_utils import add_json_flag, enable_json, is_json, json_log, log, die
```
In the `if __name__ == "__main__"` block, add to argparse:
```python
add_json_flag(parser)
args = parser.parse_args()
if args.json:
enable_json()
```
### Step 3: Replace each output point
Apply the categorization from Step 1. Key patterns:
**Simple informational:**
```python
# Before
print(f"Connected to {device}")
# After
log(f"Connected to {device}", event="connected", device=device)
```
**Error + exit:**
```python
# Before
print("Device not found")
sys.exit(1)
# After
die("Device not found")
```
**Daemon readiness (first output after initialization):**
```python
# Before
print(f"Server running on port {port}")
# After — json_ready() only emits in JSON mode, so always call it + human fallback
json_ready(port=port)
log(f"Server running on port {port}", event="ready", port=port)
```
**Status lines (\r overwrite):**
```python
# Before
print(f"\r HR {hr} RMSSD {rmssd:.1f}", end="", flush=True)
# After
if is_json():
json_log("status", hr=hr, rmssd=rmssd)
else:
print(f"\r HR {hr} RMSSD {rmssd:.1f}", end="", flush=True)
```
**Human-only output (banners, usage examples):**
```python
if not is_json():
print("Usage: send {\"type\": \"join\", \"name\": \"Alice\"}")
```
### Step 4: Verify
1. Run `python script.py --help` — confirm `--json` flag appears
2. Run `python script.py --json` — confirm first line is valid JSON
3. Grep for remaining raw `print(` calls — ensure each is guarded or intentional
## Event Name Conventions
Use snake_case, be descriptive, keep them grep-friendly:
| Category | Events |
|----------|--------|
| Lifecycle | `ready`, `shutdown`, `connected`, `disconnected` |
| Data | `hr`, `status`, `metric`, `heartbeat` |
| Errors | `error`, `retry` |
| Actions | `recording_started`, `recording_stopped`, `preset_change` |
| Progress | `scanning`, `connecting`, `downloading`, `importing` |
## Scaffolding an Open-Source Package
When the user wants a distributable package, scaffold this structure:
```
cli-utils-agent/
├── pyproject.toml
├── LICENSE # MIT by default, ask user
├── README.md
├── src/
│ └── cli_utils_agent/
│ ├── __init__.py # re-exports all public API
│ └── core.py # the implementation
├── tests/
│ ├── __init__.py
│ ├── test_json_log.py
│ ├── test_die.py
│ ├── test_log.py
│ └── test_add_json_flag.py
└── .github/
└── workflows/
└── test.yml # CI with pytest
```
### `__init__.py` — re-export public API
```python
# src/cli_utils_agent/__init__.py
from .core import (
enable_json, is_json, json_log, json_error, die,
add_json_flag, log, json_ready,
)
__all__ = [
"enable_json", "is_json", "json_log", "json_error", "die",
"add_json_flag", "log", "json_ready",
]
```
### README.md template
Generate a README with: project name, one-line description, install instructions (`pip install cli-utils-agent`), quick usage example showing `add_json_flag` + `enable_json` + `log()`, API reference table listing all exports with one-line descriptions, and a link to the research background.
### pyproject.toml template
```toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "cli-utils-agent"
version = "0.1.0"
description = "Add agent-friendly --json NDJSON output to any Python CLI"
readme = "README.md"
license = "MIT"
requires-python = ">=3.10"
classifiers = [
"Development Status :: 4 - Beta",
Related in AI Agents
skill-development
IncludedComprehensive meta-skill for creating, managing, validating, auditing, and distributing Claude Code skills and slash commands (unified in v2.1.3+). Provides skill templates, creation workflows, validation patterns, audit checklists, naming conventions, YAML frontmatter guidance, progressive disclosure examples, and best practices lookup. Use when creating new skills, validating existing skills, auditing skill quality, understanding skill architecture, needing skill templates, learning about YAML frontmatter requirements, progressive disclosure patterns, tool restrictions (allowed-tools), skill composition, skill naming conventions, troubleshooting skill activation issues, creating custom slash commands, configuring command frontmatter, using command arguments ($ARGUMENTS, $1, $2), bash execution in commands, file references in commands, command namespacing, plugin commands, MCP slash commands, Skill tool configuration, or deciding between skills vs slash commands. Delegates to docs-management skill for official documentation.
reprompter
IncludedTransform messy prompts into well-structured, effective prompts — single or multi-agent. Use when: "reprompt", "reprompt this", "clean up this prompt", "structure my prompt", rough text needing XML tags and best practices, "reprompter teams", "repromptception", "run with quality", "smart run", "smart agents", multi-agent tasks, audits, parallel work, anything going to agent teams. Don't use when: simple Q&A, pure chat, immediate execution-only tasks. See "Don't Use When" section for details. Outputs: Structured XML/Markdown prompt, quality score (before/after), optional team brief + per-agent sub-prompts, agent team output files. Success criteria: Single mode quality score ≥ 7/10; Repromptception per-agent prompt quality score 8+/10; all required sections present, actionable and specific.
adaptive-compaction
IncludedAdaptive add-on policy and recovery layer that decides WHEN to compact, prune, snapshot, or fork -- replacing fixed-percent auto-compaction across Claude Code, Codex, and MCP-capable hosts. Trigger on auto-compact timing or damage: "when should I compact", "is it safe to compact now or start a fresh session", "auto-compact fires too early/mid-task", "switching to an unrelated task but the window still has space", "context rot", "answers get worse the longer the session runs", "the agent forgot the plan or my decisions after it summarized", "add a layer on top that manages context without changing the agent", raising autoCompactWindow to give the policy room, or installing/tuning a cross-tool compaction policy or PreCompact hook -- even when "compaction" is never said but the problem is context-window pressure or post-summarization memory loss. Do NOT use to summarize a conversation, build RAG, write a summarization prompt (decides WHEN not HOW), or answer max-context-length trivia.
agent-skill-creator
IncludedCreate cross-platform agent skills from workflow descriptions. Activates when users ask to create an agent, automate a repetitive workflow, create a custom skill, or need advanced agent creation. Triggers on phrases like create agent for, automate workflow, create skill for, every day I have to, daily I need to, turn process into agent, need to automate, create a cross-platform skill, validate this skill, export this skill, migrate this skill. Supports single skills, multi-agent suites, transcript processing, template-based creation, interactive configuration, cross-platform export, and spec validation.
llm-wiki
IncludedUse when building or maintaining a persistent personal knowledge base (second brain) in Obsidian where an LLM incrementally ingests sources, updates entity/concept pages, maintains cross-references, and keeps a synthesis current. Triggers include "second brain", "Obsidian wiki", "personal knowledge management", "ingest this paper/article/book", "build a research wiki", "compound knowledge", "Memex", or whenever the user wants knowledge to accumulate across sessions instead of being re-derived by RAG on every query.
skill-master
IncludedAgent Skills authoring, evaluation, and optimization. Create, edit, validate, benchmark, and improve skills following the agentskills.io specification. Use when designing SKILL.md files, structuring skill folders (references, scripts, assets), ingesting external documentation into skills, running trigger evals, benchmarking skill quality, optimizing descriptions, or performing blind A/B comparisons. Keywords: agentskills.io, SKILL.md, skill authoring, eval, benchmark, trigger optimization.