Python reference SDK for the Agent Command Line Interface Protocol
Project description
rendo-aclip
rendo-aclip is the canonical Python SDK for ACLIP, the Agent Command Line Interface Protocol.
It keeps normal CLI usage natural while standardizing the parts agents actually depend on:
- progressive Markdown help
- app-defined success output plus structured error envelopes
- sidecar manifests for distribution metadata
- packaging helpers for shipping runnable CLI artifacts
Install
Canonical package:
pip install rendo-aclip
Short-name official alias:
pip install aclip
Both install paths are first-party and synchronized. The import path is the same either way:
from aclip import AclipApp
If you want the canonical dependency name in project manifests, prefer rendo-aclip.
If you want the shortest install command, aclip is the official alias.
Smallest End-to-End CLI
main.py
from aclip import AclipApp
def create_app() -> AclipApp:
app = AclipApp(
name="notes",
summary="A minimal notes CLI.",
description="Create and list notes from a small local CLI.",
)
def create_note(title: str, body: str) -> dict:
"""Create a note in a local JSON store.
Args:
title: Title for the note.
body: Body text for the note.
"""
return {"note": {"title": title, "body": body}}
app.group(
"note",
summary="Manage notes",
description="Create and inspect notes.",
).command(
"create",
handler=create_note,
examples=["notes note create --title hello --body world"],
)
return app
app = create_app()
cli.py
from aclip import run_cli
from main import app
run_cli(app)
If you prefer lazy initialization at process start, the launcher also accepts the factory directly:
from aclip import run_cli
from main import create_app
run_cli(create_app)
Run it like a normal CLI:
python cli.py --help
python cli.py note --help
python cli.py note create --help
python cli.py note create --title hello --body world
The final command prints app-defined success output:
- strings stay plain text
- objects and arrays are emitted as plain JSON
AclipApp.name is the canonical CLI command token, not a display title. Keep it executable-safe, with no spaces.
version is optional during local authoring. Set it before manifest build, packaging, publish, skill export, or the default root --version / -V / -v surface, which prints <cli-name> <version>.
--help / -h remain protocol-reserved discovery flags, while --version / -V / -v are only default root fallbacks and become author-owned again after a concrete command path is selected.
When one author-owned argument should accept multiple aliases, declare flags=(\"--long\", \"-S\") on ArgumentSpec instead of splitting aliases across multiple parameters.
Build A Distributable CLI
From a dedicated build script:
import aclip
artifact = aclip.build("main:app")
print(artifact.binary_path)
print(artifact.manifest_path)
build(...) is the shortest first-class path. "main:app" is the runtime import target the packaged binary will execute.
That is why the recommended pattern is a separate build.py script instead of having the app object “build itself”.
If you prefer to keep initialization behind a function, ACLIP also supports an explicit factory target:
import aclip
artifact = aclip.build(factory="main:create_app")
Python also supports a shorthand when you already imported a top-level factory:
import aclip
from main import create_app
artifact = aclip.build(create_app)
If you want the fully explicit name, build_cli(...) is the same API.
Authentication
ACLIP now standardizes a minimum auth contract around portable credential declarations and an optional reserved auth control plane.
from aclip import (
AuthCommandConfig,
AuthNextAction,
AuthStatus,
CredentialSpec,
auth_status_result,
build_auth_control_plane,
)
credentials = [
CredentialSpec.env(
name="notes_token",
env_var="ACLIP_NOTES_TOKEN",
description="Remote notes API token.",
required=True,
),
CredentialSpec.file(
name="notes_token_file",
path=".secrets/notes-token.txt",
description="Optional local token file.",
),
]
auth = build_auth_control_plane(
AuthCommandConfig(
login_description="Login to the author-defined remote service.",
login_examples=["notes auth login"],
login_handler=lambda _payload: {"status": "logged_in"},
status_description="Inspect current auth state.",
status_examples=["notes auth status"],
status_handler=lambda _payload: auth_status_result(
AuthStatus(
state="authenticated",
principal="dev@rendo.cn",
next_actions=[
AuthNextAction(
summary="Refresh before expiry",
command="notes auth login",
)
],
),
guidance_md="Credential is valid. Refresh before running long-lived jobs.",
),
logout_description="Logout from the author-defined remote service.",
logout_examples=["notes auth logout"],
logout_handler=lambda _payload: {"status": "logged_out"},
)
)
Diagnostics
ACLIP also provides a reserved optional doctor control plane and helper payload builders for stable agent-facing checks.
from aclip import (
DoctorCheck,
DoctorCommandConfig,
DoctorRemediation,
build_doctor_control_plane,
doctor_result,
)
doctor = build_doctor_control_plane(
DoctorCommandConfig(
check_description="Run author-defined environment checks.",
check_examples=["notes doctor check"],
check_handler=lambda _payload: doctor_result(
checks=[
DoctorCheck(
id="credentials",
status="warn",
severity="medium",
category="auth",
summary="Credential is missing or expired.",
hint="Run the login flow before retrying.",
remediation=[
DoctorRemediation(
summary="Refresh the credential.",
command="notes auth login",
automatable=True,
)
],
)
],
guidance_md="Fix the auth check first, then rerun the original command.",
),
fix_description="Apply author-defined fixes for failed checks.",
fix_examples=["notes doctor fix"],
fix_handler=lambda _payload: {"checks": []},
)
)
Export Agent Skills Packages
ACLIP can export developer-authored skill packages while keeping CLI and command metadata aligned as anchors.
There are two different hook scopes:
add_cli_skill(...)Attach one skill package to the whole CLI. Use this for top-level usage strategy, cross-command navigation, auth/doctor preparation, or other whole-tool guidance.add_command_skill(...)Attach one skill package to one command path. Use this for command-specific best practices, prerequisites, recovery steps, or multi-step invocation guidance.
These hooks do not change normal runtime behavior.
They do not automatically print skill text when the CLI runs.
They only register export-time linkage so that export_skills(...) knows which developer-authored packages to materialize.
from pathlib import Path
from aclip import export_skills
from main import create_app
app = create_app()
skills_root = Path("skills")
app.add_cli_skill(skills_root / "notes-overview")
app.add_command_skill(
("note", "create"),
skills_root / "note-create-best-practice",
metadata={"owner": "docs"},
)
artifact = export_skills(app, output_dir=Path("dist") / "skills")
print(artifact.index_path)
What happens here:
app.add_cli_skill(...)registers one whole-CLI packageapp.add_command_skill(...)registers one command-bound packageexport_skills(...)validates each source package- ACLIP copies those packages into the output directory
- ACLIP injects anchor metadata into
SKILL.md - ACLIP writes a
skills.aclip.jsonindex beside the exported packages
Each source package must contain a developer-authored SKILL.md.
Important boundary:
- hook registration does not install anything into a user workspace
export_skills(...)is an explicit optional API- if you want
initor another command to copy exported skills into a project, that copy step is still your command logic, not automatic ACLIP runtime behavior
In a conventional project layout, ACLIP infers:
- project root
- source root
- executable name
src/ is optional. Advanced overrides such as project_root, source_root, and extra_paths are still available for monorepos or non-standard layouts, but they are no longer the default path.
What You Get
AclipAppfor tree-shaped CLI authoring- direct
handler=...registration and decorator authoring app.run(...)for direct execution in tests or custom hostsrun_cli(...)for the default launcher path without manualsys.argv[1:]build(...)for the shortest packaging path, withbuild_cli(...)as the explicit equivalentexport_skills(...)for Agent Skills-compatible package export from CLI-level and command-level hooks
When To Use ACLIP
Use rendo-aclip when you want a CLI that still feels natural to command-line users while giving agents:
- predictable help disclosure
- predictable machine-readable failures
- a stable packaging and distribution path
If your goal is only a human-first CLI with free-form text output, ACLIP is probably more structure than you need.
Python vs TypeScript
The Python and TypeScript SDKs now share the same primary story:
- define
appinmain - launch with
run_cli(app)/runCli(app) - package with
build("main:app")
One intentional difference remains: Python also supports build(create_app) for a top-level factory function. TypeScript does not expose the same shortcut because a JavaScript function object is not a stable packaging import target on its own.
Repository
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rendo_aclip-0.3.4.tar.gz.
File metadata
- Download URL: rendo_aclip-0.3.4.tar.gz
- Upload date:
- Size: 39.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
179982f713b1ad1d1dff2418728a96bf9824bade5956860c0e3646abe7416a96
|
|
| MD5 |
d81229598ebf4b5a2c5a975a4b6cba12
|
|
| BLAKE2b-256 |
2383f0e6e6e49f7d43ee3c721cd09b7b60d433c6af0620e79fa38543ad74f8b7
|
File details
Details for the file rendo_aclip-0.3.4-py3-none-any.whl.
File metadata
- Download URL: rendo_aclip-0.3.4-py3-none-any.whl
- Upload date:
- Size: 30.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
799ffb89a3a55545ba1f6e0e3d0081d4adbb89a626fb5ddf2b22ceaf175b9f87
|
|
| MD5 |
84d5bace6464cc34a724ba3ecec5bd8b
|
|
| BLAKE2b-256 |
8e62de323dd3ee618a0fe30c943449a911e8d621e3949a6394351788d622cd04
|