Skip to main content

overpower

A CLI that installs curated AI Frameworks — named bodies of agent equipment from a single upstream — into a repository or onto a machine.

uvx overpower@latest install --skill panlabs-python-standards --runtime claude-code

Three commands, and they answer three questions. list says what there is, install writes it, doctor says whether what was written is still what was written.

Typed bare in a terminal, overpower opens the banner and the help and exits 0; under a pipe the banner stays behind and the help goes through alone, so grep and a file get something readable. overpower --version answers the version that arrived, read from the installed metadata rather than from a constant — which is what makes it evidence that the package landed intact.

Always @latest

uvx freezes the version on first use, with no TTL. Since the version of overpower is the version of the catalog it embeds, a bare uvx overpower serves a catalog that can never age out. @latest is a correctness requirement, not README style.

list — what there is

Bare, it prints the whole embedded catalog in three blocks:

uvx overpower@latest list
block what it holds how it installs
AI Frameworks a body of equipment from one upstream whole, never a slice of one
Pool skills artifacts curated to stand alone alone, by name
Bundles a named set of pool artifacts expands to exactly what its manifest names

Every item arrives with its size, its file count and its description whole — never truncated, at 80 columns and at 60, because the description is what the decision to install is made on.

One selector opens one item, and each takes one name:

uvx overpower@latest list --ai-framework matt-pocock   # every artifact inside it, typed
uvx overpower@latest list --skill panlabs-python-standards
uvx overpower@latest list --bundle api-python

--skill and --bundle carry the same short forms here as on install, -s and -b. Two selectors on one line is a question with two answers, and exits 2 naming both flags. A name outside the catalog exits 2 with the closed list in the message: the list is closed, so the defect is in what was typed.

install — write it

uvx overpower@latest install --ai-framework matt-pocock --runtime claude-code,cursor

The three selectors mix freely on one line, and each accepts a comma-separated value, a repeated flag, or both — they accumulate either way:

flag short unit
--ai-framework an AI Framework, installed whole
--bundle -b a bundle, expanded to the pool artifacts it names
--skill -s one pool skill

--ai-framework has no short flag on purpose: -f is spoken for by --force, and a letter that means one thing on one line and another elsewhere is worse than typing the word.

A line that mixes all three produces one plan, in a fixed order — framework, then bundle, then individual artifact. Where two selectors would write the same destination the order decides it rather than an error: the individual artifact is the most specific unit, so it is the last write and its content is what survives.

Runtimes

--runtime takes the keys of a closed table of 76 runtimes and has no default. A line that names something to install and no runtime to equip exits 2 rather than guessing; a key outside the table exits 2 naming the whole set. A named runtime whose directory does not exist yet is created, never skipped.

Several runtimes read the same directory: nineteen of the seventy-six read .agents/skills. When they do, the plan says so — it prints the path and who reads it, so a selection that lands in one shared place says that, instead of promising one installation per runtime.

$ overpower install --skill panlabs-python-standards --runtime claude-code,cursor,codex --dry-run

╭─ plan ───────────────────────────────────────────────────────────────────────╮
│                                                                              │
│  panlabs-python-standards  1 skill                                           │
│    .claude/skills/  ← claude-code                                   8 files  │
│    .agents/skills/  ← codex, cursor                                 8 files  │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯

overpower install typed bare in a terminal opens a wizard instead of refusing: artifacts, then scope, then runtimes, then confirmation. The order is mechanical, not aesthetic — the runtime step probes the target root, so it cannot be asked before the scope is known. It builds the same request the flags do.

Scope

Inside a git repository the default is the repository. Outside one a flag line refuses, exit 2, unless --global/-g says explicitly to write under the home directory: the git is the manifest only holds where there is git, and nothing else on the machine would audit what a silent write left behind. The wizard reaches the same explicitness from the other side — outside a repository it does not ask a question that has one legal answer, and goes global without the step.

In project scope every landing is a real copy. Under core.symlinks=false — a value git detects and records into the clone — a committed link checks out as an ordinary text file, and the equipment is broken for whoever cloned.

In global scope each selection climbs a ladder: the first destination in the table's own order receives the copy, and every destination after it becomes a relative symlink to it — relative, so the link survives $HOME moving. On Windows the same rung is a junction, which needs no privilege. Where neither can be created, the write degrades to a real copy, says so as a warning, and still exits 0: nothing is lost either way.

--force/-f is a global-scope gate and nothing else. A destination that already exists is refused, exit 3, unless it says to overwrite — global scope has no git status to reveal or undo a clobbered write. Both that refusal and a runtime with no destination in the requested scope (eve and promptscript have none globally) are detected before a single byte is written.

The plan comes first

Every run prints the plan — every path, and who reads each one — before writing anything. In a terminal it then asks; --yes/-y skips that confirmation and nothing else. Off a terminal it does not ask at all, so the same line runs identically in CI.

--dry-run resolves everything, prints the same plan, mirrors the exit code and leaves nothing behind, not even an empty directory.

--from — any GitHub repository

uvx overpower@latest install --from https://github.com/owner/repo --skill some-skill --runtime codex

The vendored catalog ages by construction, and --from is the escape hatch that does not wait for a curation refresh. It points --skill at any GitHub repository, with no registration, and it is exclusive: with it, only the remote is consulted, which extinguishes the question of precedence rather than answering it. It holds for --skill alone — a skill is the one unit that exists in the market, while a bundle and an AI Framework only exist in a repository that already knows the overpower — and a line naming either of them alongside --from is refused by name before anything is fetched.

The URL is a search root, not an address. The repository root, a subfolder, or the skill's own folder all give the same result. tree/<ref>/<path> pins a branch, a tag or a full SHA, so reproducibility comes free with the address someone pasted.

Obtention uses the local git as transport and reuses whatever credential it already has, falling back to the anonymous tarball — standard library only — so no third-party binary is a requirement. There is no cache: remote content is fresh by decision.

doctor — is it still what it was

uvx overpower@latest doctor

Two halves in one output. The terminal half reports tty, colour, width and NO_COLOR — the four facts that explain a screen that came out strange, without a round trip. The integrity half reads the runtime table in both scopes, because the target carries no manifest and the closed table is therefore the only thing that knows where equipment can be. That is also why there is no --global here: one flag switching between the halves would make it two outputs. Outside a git repository it still answers, unlike install.

Three checks, and each pays a hole nothing else closes:

  • core.symlinks=false breaking links — the case where git status stays clean while the equipment is a text file. The git lies, and doctor is what contradicts it. Both places the value can live are read, in git's own precedence order.
  • A link that does not resolve — invisible equipment: the listing shows a name with nothing behind it.
  • Copies of one artifact that disagree — the debt taken on when project scope chose to copy instead of link.

Exit 3 when it found something, 0 when it did not, which is what makes it usable as a CI gate next to --dry-run.

Exit codes

code meaning
0 did what was asked
1 could not run
2 you invoked me wrong
3 ran, and the answer is no

The axis between 2 and 3 is whose defect it is, and it is what makes both usable in a pipeline. A --runtime outside the table is 2; a --runtime in the table with no destination in the requested scope is 3. A --from whose search root could not be obtained is 1, and the transport's own error is passed through because it is the one that names the problem; obtained, searched, and the skill is not there — or is there twice — is 3.

A traceback never reaches the terminal: an unhandled exception becomes an error panel and exits 1, saying it is a bug in the overpower and not in what was typed.

The op alias collides

op is the command of the 1Password CLI. Aliasing op=overpower shadows it. If you use both, pick another alias — this is written down rather than left to be discovered:

alias opw='uvx overpower@latest'

Development

Four commands, and they are the whole loop. There is no task runner, and the absence is deliberate: uv already does what one would add.

uv run ruff format --check .          # formatting
uv run ruff check .                   # lint
uv run --group typecheck pyright      # types, strict
uv run pytest                         # tests

The same four run in CI, from the same lockfile, so "it passed locally" and "it passed in CI" mean the same thing.

Local hooks

lefthook install     # once per clone; worktrees inherit

The hook is the shortcut, not the gate — the gate is the ruleset on main, and a ruleset has no --no-verify. lefthook and gitleaks are equipment of the machine, not of the repository; a clone on a machine without them loses the shortcut by design.

Coverage

Ephemeral by decision: no threshold, no badge, nothing in pyproject.toml. One command, for when the question is "what has no test at all":

uv run --with pytest-cov pytest --cov=src/overpower --cov-report=term-missing

Screens

Recorded screens live in tests/snapshots/, one file per screen, at 80 and 60 columns, without colour. They render a fixture and not the shipped catalog, so a content refresh does not rewrite them. Rewriting them is an explicit act:

uv run pytest --snapshot-update tests/test_screens.py

Releasing

The version is a literal in pyproject.toml, moved by hand:

uv version --bump patch      # or minor / major
uv run towncrier build --version "$(uv version --short)"

Merging that into main is what publishes: the tagger workflow creates v<X> and dispatches the release. A merge that does not move the version publishes nothing.

Curation

Refreshing the catalog is an act, not a job. A gate blocks what this repository controls; what depends on a third party is verified here, by hand, on purpose.

Refreshing the vendored content

The trees under src/overpower/content/ are vendored at a fixed upstream reference, which NOTICE records per origin. A refresh is:

  1. Read the upstream's own manifest at the new reference to get the set — for matt-pocock, the skills array of .claude-plugin/plugin.json, never the version field beside it, which has been measured standing still while the array moved.
  2. Replace the tree, applying the curation transform: the slice excludes what the upstream declares unshipped, and the shape is the one the target discovers, because the transformation happens at curation and never in the product.
  3. Update NOTICE — reference and commit per origin — and licenses/ if the upstream licence file moved.
  4. Run the four development commands, plus the network test below.
  5. Bump the version. By rule 5 the version of the overpower is the version of the catalog, so a refresh nobody can install is not a refresh.

Tests that touch the real GitHub

They exist, they are documented, and they run in no CI job — not on a pull request and not on a release:

OVERPOWER_NETWORK_TESTS=1 uv run pytest -m network

With the variable set, the skip condition can no longer be satisfied — a network test that gets renamed or lost turns red instead of disappearing in silence.

Where the reasoning lives

Every position in this repository was decided in a ticket, and the ticket is where the argument is. The map is Mapa: overpower v0.1.0 publicada no PyPI.

Document Role
docs/agents/domain.md Vocabulary, model rules, curation criteria, axioms
docs/agents/workflow.md Branch policy, gates, autonomous implementation mode
docs/agents/testing.md What is a double, what runs for real, how screens are asserted
docs/adr/ The decisions that read as arbitrary until you know why

Licence

MIT. Attribution owed to vendored upstreams travels in NOTICE, which names each origin and the reference it was taken at, and in licenses/, which carries their licence files verbatim. PEP 639 places both in dist-info/licenses/ — inside the wheel, never in your repository.

Download files

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

Source Distribution

overpower-0.1.0.tar.gz (361.7 kB view details)

Uploaded Source

Built Distribution

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

overpower-0.1.0-py3-none-any.whl (290.8 kB view details)

Uploaded Python 3

File details

Details for the file overpower-0.1.0.tar.gz.

File metadata

  • Download URL: overpower-0.1.0.tar.gz
  • Upload date:
  • Size: 361.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","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}

File hashes

Hashes for overpower-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b2a094d0d7220f2c6e4bfcda49afae0e08c20d1709aafc22019011b341b9e5e7
MD5 bf39a62aaf9ee1973cfbb7a291993790
BLAKE2b-256 1bd5e94ee5973367d89a9a17240e1bda84ad76d02d4f676d8704d74cbcf7be1d

See more details on using hashes here.

File details

Details for the file overpower-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: overpower-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 290.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","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}

File hashes

Hashes for overpower-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 11eb0a4a70b36bce87222637ba6690d977a4216bed2d010d7fb678bbca914712
MD5 3e6b087aed97afc355ad41cab53d29d7
BLAKE2b-256 53b5bfe188a8fe01277ab438edc0be18de6a5eb918cb234994f6d37fe4f6754a

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