Skip to main content

aicp

AI commit + push, with a git-verified result summary.

aicp runs an AI coding CLI to write your commit message(s) and push, trying a fallback chain of six CLIs — copilot → agy → codex → claude → vibe → grok — until one exits 0; anything not installed is skipped. It sends that CLI two literal prompts, /commit then /safe-git-push.

The part that matters: aicp never trusts the CLI's own account of what happened. An AI CLI can print "pushed!" and exit 0 while /safe-git-push quietly aborted inside it. So every number in the result summary — new commits, ahead/behind, whether the branch is actually in sync — is read back from git itself after the CLI is done, never taken from its output. A failed git fetch is never read as "already in sync" either: a stale remote-tracking ref resolves just fine and would otherwise report a clean push that never reached the remote.

Install · Set up skills · Run it · --undo · Automation / CI · Configuration · Safety · Platform support

Requirements

  • Python 3.10 or newer
  • uv — the install path below
  • git
  • At least one of the six AI CLIs above on PATH

The Python package itself has no runtime dependencies.

Install

uv tool install aicp-cli             # latest release
uv tool install aicp-cli==X.Y.Z      # pin to a specific version

The distribution is aicp-cli; the command it installs is aicp. (The plain aicp name on PyPI belongs to an unrelated 2021 project — don't install it.) Replace X.Y.Z with the release version you want; re-running either command switches an existing install to that version.

uv tool upgrade aicp-cli
uv tool uninstall aicp-cli

Set up skills

aicp --config   # -> Skills

/commit and /safe-git-push only mean something if a skill by that exact name exists in the CLI's own config directory — otherwise the CLI receives a slash command it has never heard of and improvises. aicp ships byte-identical copies of both skills and installs them for you, but it never overwrites a skill you already have: a file with no aicp version marker next to it is treated as yours and left alone. If you already have a better /commit for this repo, it stays.

Targets follow each CLI's own config directory, not its binary name — agy (this project's name for the Gemini CLI) reads ~/.gemini, not ~/.agy:

CLI Config dir /commit installed? /safe-git-push installed?
claude ~/.claude No — keeps your existing commands/commit.md Yes
codex ~/.codex Yes Yes
copilot ~/.copilot Yes Yes
agy (Gemini CLI) ~/.gemini Yes Yes
vibe ~/.vibe Yes Yes
grok $GROK_HOME when set, otherwise ~/.grok Yes Yes

claude is the one exception: it already resolves /commit from its own commands/commit.md, so aicp never installs a competing definition under skills/ there — installing one would just shadow the one Claude already uses. Every other CLI gets both skills.

A CLI whose config directory doesn't exist at all is skipped, never created — aicp only ever installs into a CLI you've actually set up.

Fallback results and quota limits

The opening run panel prints the resolved chain, and the commit panel and final RESULT table name the CLI that handled each step (— when skipped). When a CLI emits a supported, exact quota/rate-limit signal, aicp records the outcome as quota, notifies through the usual notification path, and excludes that CLI from the rest of that one commit/push flow. The exclusion also persists: the CLI stays skipped for AICP_QUOTA_COOLDOWN seconds (default one hour, state in ~/.aicp/quota.json), because a token or rate-limit wall normally stands for hours and every run inside that window would otherwise burn a full budget per step on a CLI that cannot succeed. A skipped CLI prints how long is left; AICP_QUOTA_COOLDOWN=0 switches the cooldown off entirely, and deleting the file clears it.

Only the quota outcome starts a cooldown. A timeout does not — a CLI that hangs on its rate limit instead of exiting is indistinguishable from one merely running long, and sidelining it for an hour on that guess costs more than the retry does.

Exact detection is intentionally narrow. It is supported for Codex, Claude, Vibe, and Grok only; Copilot and agy have no verified quota signature, so a nonzero exit from either remains an ordinary failure and is still eligible for the next step.

Run it

The whole command surface is two things to remember:

aicp             # commit, then push
aicp --config    # settings, skills, health check — everything else lives here

A plain aicp run: checks whether anything is pending (skipping the AI CLI entirely on a clean, already-in-sync repo), scans for secrets, runs /commit through the fallback chain, then /safe-git-push the same way, then prints the git-verified result table described above. -v/--verbose streams each CLI's raw output live instead of showing a spinner.

aicp run: commit, push, and the git-verified result table

aicp --config is one menu for everything that isn't "commit and push right now": which steps run, message language, fallback CLI order, the skills install/upgrade view, and a health check.

--undo

aicp --undo

Runs git reset --soft HEAD^ on the last commit — the escape hatch for a bad commit message or a wrong stage. Changes land back in the index, not lost, not pushed. It never calls an AI CLI and refuses outright (HEAD untouched) in four cases, because once a commit reaches the remote other clones or CI may already be building on it:

  • there's no branch to compare against (detached HEAD),
  • there's no parent commit to reset onto,
  • the last commit is already on the remote,
  • the remote can't be verified at all (deleted remote, failed fetch, never pushed) — "can't verify" is treated as the risky case, never as "safe."

Automation / CI

Everything below is a non-interactive escape hatch for scripting; day-to-day use is the two commands above.

aicp --doctor --json          # skill-install status for every configured CLI, as JSON
aicp --install-skills --yes   # install what's missing, upgrade what's outdated
aicp --install-skills --force # also replace files aicp doesn't recognize

--doctor --json reports, per CLI and per skill: the target path and whether it's missing, current, an outdated aicp copy, someone else's file, or the CLI itself isn't configured — the same view --config's Skills screen shows, without a terminal.

--install-skills --yes installs anything MISSING and upgrades anything older than the version aicp ships, exactly like the interactive Skills view — and it never touches a file aicp doesn't recognize. Only --force does that, and even then the original is moved aside to <name>.bak (numbered .bak.1, .bak.2, … so a second forced install never clobbers the first backup) before aicp writes its own copy.

Releasing

.github/workflows/release.yml runs on a v* tag. It repeats the full lint/test/build pass, installs the wheel into a throwaway venv, and refuses to upload unless that wheel reports the version being tagged — so a tag that disagrees with pyproject.toml fails before anything reaches PyPI. It then publishes with Trusted Publishing (OIDC — there is no API token stored in this repo) and attaches the wheel, sdist and SHA256SUMS to the GitHub release.

Checksums are generated after publishing on purpose: uv publish uploads everything in dist/, and SHA256SUMS is not a distribution.

A tag runs the workflow file as it existed at that tag, so a release that failed to publish can't be repaired by re-running the old tag — the fix isn't in that tree. Bump the version and tag again.

Configuration

The config file lives at ~/.aicp/config.json (override the path itself with AICP_CONFIG, which — being the thing that names the file — can only be set as a real environment variable). Precedence everywhere is environment > config.json > hardcoded default. The file is a JSON object, parsed as data and never sourced or eval'd, written atomically and owner-only (0600) by --config/--swap-ai; only keys matching AICP_[A-Z0-9_]* case-insensitively with a string value built from letters, digits and / . _ : @ + - survive — everything else (an unknown key, a non-string value, a value outside that charset) is skipped individually, so one bad key never costs the rest of the file. An invalid value for a known key never aborts a run — it's reported on stderr and falls back to the default.

aicp always writes keys lower_case (aicp_do_commit, not AICP_DO_COMMIT) — every key in config.example.json and any new knob added in the future follows the same convention. Reading is case-insensitive, so an existing file with AICP_-cased keys still works.

A legacy ~/.aicprc (the pre-JSON KEY=value format) is migrated into ~/.aicp/config.json automatically, once, the first time aicp runs — the old file is left in place untouched, never deleted or rewritten.

See config.example.json for a ready-to-copy template.

Variable Default What it does
AICP_DO_COMMIT 1 Run the /commit step. 0 = only push what's already committed.
AICP_DO_PUSH 1 Run the /safe-git-push step. 0 = commit and stop.
AICP_LANG en Message language: en or zh-TW, everywhere including notifications.
AICP_CLI_ORDER copilot agy codex claude vibe grok Fallback order. A prefix is enough — any roster name left out is appended after it, in roster order. An unknown or repeated name is refused outright and the default order is used.
AICP_TZ Asia/Taipei IANA zone name used to render commit timestamps. Anything else falls back to the default.
AICP_TZ_LABEL UTC+8 Cosmetic label shown beside those timestamps; not validated.
AICP_STEP_TIMEOUT (unset) Pins every CLI's per-step budget in seconds, skipping the formula and history below entirely.
AICP_TIMEOUT_BASE 180 Budget floor (seconds) — covers cold start plus a small prompt.
AICP_TIMEOUT_PER_FILE 15 Seconds added per changed or untracked file.
AICP_TIMEOUT_PER_100L 5 Seconds added per 100 changed lines in tracked files.
AICP_TIMEOUT_MAX 1800 Ceiling on the formula above. A CLI's own run history may still widen its budget past this — that's direct evidence it legitimately needs the time, not a guess.
AICP_TIMEOUT_HISTORY_LINES 500 How many recent timing-log rows are scanned when widening a budget from history.
AICP_TIMEOUT_HISTORY_MULT 1.3 Multiplier applied to a CLI's largest successful run when that exceeds the formula.
AICP_QUOTA_COOLDOWN 3600 Seconds a CLI that reported a quota/rate-limit signal stays skipped, across runs (state in ~/.aicp/quota.json). 0 switches the feature off; anything not a plain integer in 1..604800 falls back to the default.
AICP_SKIP_SECRET_SCAN (unset) 1 bypasses the pre-commit secret scan for one run — the documented escape for a false positive.
AICP_CONFIG ~/.aicp/config.json Which file this loader reads. Environment-variable only — a file can't rename itself.
AICP_TG_SEND ~/.claude/scripts/tg-send.sh The Telegram send script run at the end of a notification. Environment-variable only — refused if set in config.json.
AICP_TIMING_LOG ~/.aicp/timing.log Where per-CLI timing rows are appended (rotated at 5 MB, 5 kept). Environment-variable only — refused if set in config.json.

AICP_TG_SEND and AICP_TIMING_LOG are refused from config.json on purpose: both name a path that then gets executed (AICP_TG_SEND, run as a script) or written and rotated (AICP_TIMING_LOG, mkdir -p / >> / a rename). A config file is exactly the kind of thing that can arrive synced from someone else's dotfiles repo, so anything that becomes a command or a filesystem sink stays a real-environment-only decision — set it in your shell, not the file.

Safety

Before any AI CLI runs, aicp scans everything the run could commit for likely secrets: the added lines of the pending diff, every tracked file git reports as binary, and every untracked file — since aicp never runs git add itself, a brand-new file with a pasted secret is exactly the case that would otherwise slip through unscanned. A hit stops the run before any AI CLI is called, and only ever prints the file, line number and the pattern's name — never the matched text itself, so a real secret can't reach your terminal, a log, or a Telegram notification through this path.

Seven fixed patterns are checked (OpenAI-style sk-… keys, GitHub PATs and App tokens, AWS access key IDs, bearer tokens, and PEM private-key blocks) — deliberately prefix/format checks only, with no entropy heuristic: that was tried and rejected upstream as the main source of false positives (this project's own API-key-shaped test fixtures tripped it). A false positive is bypassed once with AICP_SKIP_SECRET_SCAN=1.

A file the scanner can't read as text — genuinely binary, or a UTF-16 .env full of NUL bytes — is never silently skipped: it's reported as "not scanned, verify manually" so an unreadable file never reads as a clean one.

Platform support

Tested in CI on macOS, Linux, and Windows, full test suite on all three — no platform is a reduced or best-effort target.

Platform Notes
macOS No caveats.
Linux No caveats.
Windows Every AI CLI ships as an npm .cmd/.bat shim, which Windows can't launch directly (CreateProcess doesn't honor PATHEXT and can't run a batch file itself) — aicp resolves the real executable and, for a shim, launches it through cmd.exe itself rather than shell=True, so no user-controlled text ever builds a shell command line. Ctrl+C is forwarded as CTRL_BREAK_EVENT rather than delivered directly (Windows has no "foreground process group" concept), so a CLI that ignores that signal may not stop as cleanly as it would elsewhere.

On POSIX, a per-CLI timeout signals the CLI process itself, not any grandchildren it spawned. On Windows, terminating the intermediate cmd.exe can orphan the CLI behind the shim; that high-priority defect remains open in TODO.md. Ctrl+C still targets the Windows process group.

License

MIT — see LICENSE.

Release files for aicp-cli 0.3.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aicp-cli 0.3.1
File Size Uploaded
aicp_cli-0.3.1.tar.gz 317.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for aicp-cli 0.3.1
File Interpreter ABI Platform
aicp_cli-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 421.8 kB

Release files / aicp_cli-0.3.1.tar.gz

Download URL aicp_cli-0.3.1.tar.gz
Size 317.7 kB
Tags Source
SHA-256 checksum
How to use checksums
26819364bc1dc2b7bdeef98bf06248f4f0304789adfb1ff6d43733bac2def693
BLAKE2b-256 checksum
How to use checksums
eb24620ca74a62f072c9f9446fc823d5aa9bc43158aba8e62cb60f4ef18ca8b0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / aicp_cli-0.3.1-py3-none-any.whl

Download URL aicp_cli-0.3.1-py3-none-any.whl
Size 104.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
647356ab9b924474d181458244c40d1ec3d4c50ae79a6952d346751f693a096f
BLAKE2b-256 checksum
How to use checksums
d6d0674df457bc1e8954c12ee3b9ba37767acd16373ce8fc44706db94668dac9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

0.12.0

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.4.0

2 release files

This release

0.3.1 This release

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page