Installer and license manager for the marketr-* family of Claude Code skills
Project description
marketr-installer
Installer and license manager for the marketr-* family of Claude Code skills.
What's in this pack → INDEX.md · Skills · Agents · Workflows · Scripts
What this does
marketr-installer is the bridge between a customer's purchased licenses and a working installation of marketr skills in their Claude Code environment. It:
- Reads per-purchase license files from
~/.marketr/licenses/ - Computes the merged entitlement (union by SKU)
- Installs each owned SKU as a Python package via
pip - Copies each SKU's
SKILL.md+ references into~/.claude/skills/marketr/<sku>/so Claude Code discovers them
It is also the home of the marketr CLI (install, update, add-license, status, setup, auth, init, doctor).
marketr update enforces the per-license updates_until field, and marketr status shows days-until-expiry per SKU. Lapsed-window SKUs skip the wheel fetch with a friendly renewal nudge; the installed version keeps working. See docs/plans/2026-05-10-perpetual-license-launch.md §6.1 to §6.3 for the full runtime contract, the 7-day signed-URL footgun, and the manual renewal flow.
Status
Alpha. Phase 1 of the marketplace launch plan (docs/plans/2026-05-09-marketplace-launch.md).
R2 URL signing wired 2026-05-09 (see "Operator setup — R2 signing" below).
Operator setup — R2 signing
mkt-admin license issue --method wheel signs R2 URLs at issuance time so
the customer's marketr install can pip install the wheel directly.
Only the operator needs R2 credentials — the signed URL embedded in the
license YAML is self-authenticating until expiry.
One-time install
pip install 'marketr-installer[r2]' # adds boto3
Required environment variables
Set these in your shell rc (~/.zshrc / ~/.bash_profile) so mkt-admin
can read them. They never end up in git, license YAMLs, or customer
artifacts.
| Var | Example | Where to find it |
|---|---|---|
MARKETR_R2_ACCOUNT_ID |
2f6b6043df01b12524c5752df11ffb22 |
Cloudflare Dashboard → R2 → bucket details (or the hex prefix in the bucket URL) |
MARKETR_R2_BUCKET |
skillsformarketing |
The bucket name |
MARKETR_R2_ENDPOINT |
https://2f6b6043df01b12524c5752df11ffb22.r2.cloudflarestorage.com |
The S3 API endpoint URL without the bucket suffix |
MARKETR_R2_ACCESS_KEY |
(redacted) |
Cloudflare Dashboard → R2 → Manage API Tokens → create with "Object Read & Write" scoped to the bucket |
MARKETR_R2_SECRET_KEY |
(redacted) |
Same step as above. Cloudflare shows the secret once at creation — save to a password manager immediately. |
How it behaves
| Scenario | Result |
|---|---|
All 5 env vars set, URL bucket matches MARKETR_R2_BUCKET |
URL signed with X-Amz-Signature=… query string, valid 7 days (AWS Sig v4 max) |
| Any env var missing/empty | Unsigned URL emitted + WARNING printed to stderr. License YAML is still issuable for dev/testing; install will fail at the actual download step. |
URL bucket prefix doesn't match MARKETR_R2_BUCKET |
R2SigningError — operator misconfigured something. Update skus.yaml URL templates or the env var. |
Customer perspective
Customers don't install [r2] and don't set any env vars. Their license YAML
contains a pre-signed URL; marketr install runs pip install <url> and
that's it.
URL expiry
Signed URLs are valid for 7 days (the AWS Sig v4 maximum for static
credentials). If a customer takes longer than 7 days to install after
receiving a license, run mkt-admin license issue again for the same SKU
and re-email the YAML.
Customer install (eventually)
curl -L https://marketr.<tld>/install | sh
This script will install marketr-installer (currently from a private wheel URL or git+ssh) and run marketr setup to drop the Claude Code skill into ~/.claude/skills/marketr/.
To opt into voice/sound feedback during install:
curl -L https://marketr.<tld>/install | MARKETR_WITH_VOICE=1 sh
To skip the third-party bundles entirely (minimal install):
curl -L https://marketr.<tld>/install | MARKETR_SKIP_BUNDLES=1 sh
License redemption
After a paid purchase, the operator (or, eventually, the marketr-store
backend) issues a signed license YAML and uploads it to R2 under
marketr/_redeem/<token>/license.yaml. The customer receives a
presigned GET URL (AWS Sig v4, 7-day max TTL) by email and
redeems it with one command:
marketr install --redeem 'https://<account>.r2.cloudflarestorage.com/marketr/_redeem/<token>/license.yaml?X-Amz-Signature=...'
This:
- Downloads the YAML over HTTPS (30s timeout, identifies as
User-Agent: marketr-installer/<version>so we're greppable in R2 access logs). - Verifies the embedded Ed25519 signature locally against the bundled public keys (dev + prod). The URL alone is NOT trusted — a compromised email or a typo'd URL must not be able to plant arbitrary YAML on the customer's machine.
- Writes the file atomically to
~/.marketr/licenses/<license_id>.yaml. - Continues with the normal install (same code path as bare
marketr install).
If anything fails (HTTP error, expired URL, bad signature, a license
with the same license_id is already redeemed) the command exits with
status 1 and does not run any pip install — redemption is
all-or-nothing.
The 7-day TTL is the operator's policy; if a customer's URL has
expired, the operator re-issues a fresh one (mkt-admin license issue
or, eventually, the store-backend re-signs). The redeem flow does
NOT extend or refresh URLs on its own.
Security model in one paragraph
The presigned URL is just a delivery mechanism — the trust anchor is
the Ed25519 signature inside the YAML, verified against public keys
shipped in the wheel under marketr_installer/_keys/. As long as
the operator's private key stays vaulted (~/.marketr/signing/ by
convention), any tampering anywhere along the email/network path
fails the signature check at redeem time, so the customer cannot
end up with an unauthorized license.
What marketr setup installs
| Component | Source | Lands at | Default |
|---|---|---|---|
marketr CLI + installer skill |
this package | ~/.claude/skills/marketr-installer/ + pip user bin |
always |
~/.marketr/ scaffold |
this package | ~/.marketr/{licenses,credentials,vendor,templates}/ |
always |
| Best-practice agents/commands/rules/skills | shanraisshan/claude-code-best-practice | ~/.claude/{agents,commands,rules,skills}/best-practice/ |
on, --skip-bundles to opt out |
| Best-practice CLAUDE.md template | same | ~/.marketr/templates/best-practice-CLAUDE.md (staged, never auto-applied) |
on |
| Voice/sound hooks | shanraisshan/claude-code-hooks | ~/.claude/hooks/marketr-voice/ |
off, --with-voice to enable |
Bundles are namespaced under best-practice/ and marketr-voice/ subdirs so we never collide with files the user has already authored.
Voice feedback (opt-in)
marketr voice enable # fetch + install hooks, merge bindings into ~/.claude/settings.json
marketr voice status # show enabled/disabled + binding count
marketr voice disable # remove bindings (keeps files cached, fast re-enable)
Bindings are tagged marketr-voice:<HookEvent> so disable removes only our entries — your other hooks stay intact.
Activation (online seat enforcement)
A license can grant N concurrent machine activations. The mechanism:
- The license YAML carries a
seats: Nfield (default 1; bundles likeagency_multi_clientshipseats: 5). - On
marketr install, the CLI POSTs{license_id, fingerprint}to${MARKETR_ACTIVATION_URL}/activate. The server records the activation if the cap allows, refuses with HTTP 409 if full. - Successful activations are cached at
~/.marketr/activation_<license_id>.jsonfor 30 days by default, so subsequent installs on the SAME machine don't re-call. The cache stores ONLY the activation token + seat metadata — never license content. Operators who want a tighter window (e.g. faster seat-revocation propagation) setMARKETR_ACTIVATION_CACHE_DAYS=<N>whereNis an integer in[1, 90]. Out-of-range values raise a clear error atActivationClient()construction time — a typo in a deployment env file fails loud at startup instead of silently leaking seats. - The machine fingerprint is the
install_idalready used for telemetry (~/.marketr/telemetry/.install-id). No new per-machine identifier is introduced; if you opted out of telemetry, the activation flow still uses this anonymous random id but doesn't send any telemetry events.
Backwards-compat
If MARKETR_ACTIVATION_URL is unset, activation is skipped and
marketr install prints a stderr note: "activation skipped
(MARKETR_ACTIVATION_URL not set)". Customer flows keep working until
the operator deploys the activation server. Once deployed, the env
var flips enforcement on with no client-side code change.
Customer commands
# Start using the license on this machine — happens automatically
# inside `marketr install`, no manual activation step required.
marketr install
# Free up a seat (e.g. retiring an old laptop):
marketr deactivate MKT-AGCY-MULT-CLNT
# Or release a different machine's seat (you'll need its fingerprint;
# the cap-exceeded message lists the active ones):
marketr deactivate MKT-AGCY-MULT-CLNT --fingerprint <fp>
# Inspect current usage:
marketr seats MKT-AGCY-MULT-CLNT
Cap-exceeded message
When the seat cap is full and you try to activate a new machine,
marketr install exits with:
Seat limit reached for MKT-AGCY-MULT-CLNT: 5/5 in use.
Deactivate one of: <fp_a, fp_b, fp_c, fp_d, fp_e> via
`marketr deactivate MKT-AGCY-MULT-CLNT --fingerprint <fp>`, or
contact sales for a higher-seat license.
Cache, rotation, and growth
The customer-side cache is a single small JSON file per license. The
server-side log is one <DATA_DIR>/activations/<license_id>.jsonl
per license that grows by one line per (re)activation or
deactivation. At v1 scale (a handful of machines per license over a
multi-year window) growth is negligible. Operators who want hard
caps on file size can run marketr_store.activation._compact_inplace
on a daily cron — it rewrites each file with only the live records.
Vendored bundles
Third-party content is fetched into ~/.marketr/vendor/<bundle-name>/ at frozen SHAs (see marketr_installer/bundle_fetcher.py for current pins). We don't ship the 100MB+ payload in the wheel — it's pulled at marketr setup time. Bumping a pin in code requires customers to re-run marketr setup to pick up the change.
Local development
cd marketr-installer
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest
Layout
marketr-installer/
├── pyproject.toml
├── marketr_installer/ # the Python package
│ ├── cli.py # `marketr` CLI
│ ├── admin.py # `mkt-admin` operator CLI
│ ├── schema.py # Pydantic models for license YAML
│ ├── license_loader.py # reads + merges ~/.marketr/licenses/
│ ├── pip_runner.py # subprocess wrapper for pip
│ ├── skill_copier.py # copies SKILL.md from installed packages
│ ├── bundle_fetcher.py # clones third-party bundles to ~/.marketr/vendor/
│ └── bundle_installer.py # deploys bundles into ~/.claude/ (namespaced)
├── skill/
│ └── SKILL.md # the Claude Code skill that delegates to `marketr`
├── scripts/
│ ├── install.sh # the curl|sh one-liner
│ └── skus.yaml # SKU registry (operator-side)
└── tests/
├── conftest.py
├── fixtures/licenses/ # sample license YAMLs for tests
└── test_*.py
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
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 marketr_installer-0.1.12.tar.gz.
File metadata
- Download URL: marketr_installer-0.1.12.tar.gz
- Upload date:
- Size: 413.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
68ff127cb52360a0db1597456aac82b16c7bfc305e420926df0c8cb63b504bfd
|
|
| MD5 |
54cac07a43a54d0b645e33c552d10ba2
|
|
| BLAKE2b-256 |
2dd0282c20c79f383abd82a38bfc5d9446291ce070794c33f013b824df41cf21
|
Provenance
The following attestation bundles were made for marketr_installer-0.1.12.tar.gz:
Publisher:
publish-installer.yml on don-devo/skillsformarketing
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
marketr_installer-0.1.12.tar.gz -
Subject digest:
68ff127cb52360a0db1597456aac82b16c7bfc305e420926df0c8cb63b504bfd - Sigstore transparency entry: 1792945447
- Sigstore integration time:
-
Permalink:
don-devo/skillsformarketing@181e7c9ed74ca73415e949381adda4992a387385 -
Branch / Tag:
refs/tags/marketr-installer-v0.1.12 - Owner: https://github.com/don-devo
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-installer.yml@181e7c9ed74ca73415e949381adda4992a387385 -
Trigger Event:
push
-
Statement type:
File details
Details for the file marketr_installer-0.1.12-py3-none-any.whl.
File metadata
- Download URL: marketr_installer-0.1.12-py3-none-any.whl
- Upload date:
- Size: 429.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f749af953a4ee4781387e799b18205c33846761c4c3a9ee5d9c3df6aa914fba2
|
|
| MD5 |
16aaf1e94ee566c19e75d8a5aa70185a
|
|
| BLAKE2b-256 |
c21537c0771be3fc22c4ae7618aaac0e113b450519a3ea626dd550be74b9484d
|
Provenance
The following attestation bundles were made for marketr_installer-0.1.12-py3-none-any.whl:
Publisher:
publish-installer.yml on don-devo/skillsformarketing
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
marketr_installer-0.1.12-py3-none-any.whl -
Subject digest:
f749af953a4ee4781387e799b18205c33846761c4c3a9ee5d9c3df6aa914fba2 - Sigstore transparency entry: 1792945601
- Sigstore integration time:
-
Permalink:
don-devo/skillsformarketing@181e7c9ed74ca73415e949381adda4992a387385 -
Branch / Tag:
refs/tags/marketr-installer-v0.1.12 - Owner: https://github.com/don-devo
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-installer.yml@181e7c9ed74ca73415e949381adda4992a387385 -
Trigger Event:
push
-
Statement type: