A trusted contribution protocol: improve or audit a repo you don't own and hand the owner a portable, signed change credited to a verifiable GitHub identity. The owner re-verifies with their own tooling before merge. AI optional.
Project description
Improve or audit a public repo you don't own, and hand the owner a portable, signed change whose credit is a cryptographically-verifiable GitHub identity — not a typed-in name anyone could fake. The owner re-proves it with their own tooling, at a scrutiny level they choose, before anything merges. On accept the change merges with the contributor as the git author, so they appear natively in the repo's Contributors — the identity is the credit.
A contribution rides as a plain-text spec-label anyone can verify by eye — the same card, in your terminal, a PR comment, or a README:
+--<+> crowdcoding --------------------------- CONTRIBUTION --+ | contributor @you (github.com/you) | | signed by an SSH key on that GitHub account | | changes 1 piece(s), +14 / -3, 3 files | | risk LOW (recompute to confirm) | | CLAIM - confirm it yourself: | | uvx crowdcoding verify envelope.zip --repo . | +----------------------------- cc/spec-01 - claim, not proof +
AI is optional, not the point. Bring your own model to draft the fix, or edit by hand — the value is the verifiable, owner-gated trust layer, neutral to whatever tool either side uses. It is not a bot opening unsolicited PRs; it is the inverse — opt-in and owner-gated, where the owner's own tooling decides what enters.
Verifiable identity. A contribution (and an audit) is signed with an SSH key the
contributor's GitHub account publishes; the owner verifies that signature against
github.com/<login>.keys. Credit is spoof-resistant on both sides: nobody can attribute work
to an account they don't control. Requires a GitHub account, an SSH key registered on it, and
the gh CLI — see docs/format.md for the exact scheme (any language can
verify it) and docs/action.md for the maintainer-side GitHub Action that
posts a verified "seal" on each PR.
Why not just Git's SSH commit signing?
Git can sign commits with an SSH key, and GitHub shows a green "Verified" — so why this? Because they answer different questions at different moments. Commit signing proves who authored the final commit; crowdcoding proves who authored the contribution, against which base, with what provenance, before a commit even exists — and adds what commit signing does not:
- Provenance of how it was made — hand-authored, or AI-assisted with which model, self-verified in a sandbox.
- A signed audit (in-toto/DSSE,
cosign-verifiable) as a first-class deliverable — "found nothing" is a result you can publish, not just a merged diff. - A deterministic, reproducible risk band over the diff (a published rule set, not a magic score — see docs/format.md).
- Owner re-verification — the owner re-proves safety/tests/fit with their own tooling.
crowdcoding complements commit signing; it never replaces it. On merge, the commit is authored with the contributor's GitHub identity, so native commit signing and the Verified badge apply as usual.
How it works
The contract between the two sides is the Envelope (a signed zip) plus the receiver's re-prove — never a shared agent and never blind trust. The Ed25519 signature proves only "a real keyholder produced this, unaltered"; it is anti-forgery, not a reason to trust.
contributor's model ──analyze──▶ fix pieces ──self-verify (sandbox)──▶ sign
│
envelope.zip
│
owner's model ◀──re-prove: provenance ▸ safety ▸ correctness ▸ fit── unpack
│
accept ─▶ git apply + commit (author = contributor, Assisted-By: trailer) / reject
The command set
| Command | What it does | Brain |
|---|---|---|
analyze <repo> |
Read-only scout: grade the repo and brief its top fixable issues. No fix, no envelope. | council |
contribute <repo> |
Analyze → fix → self-verify in a sandbox → emit a signed Envelope. | council |
pull <repo> |
Clone the repo into a local workspace so you can edit it by hand. | none |
pack |
Seal your workspace's manual edits into the same signed Envelope a council would produce. | none |
keygen |
Create or show your Ed25519 signing key — prints the public key only. | none |
inspect <envelope> |
Read an Envelope safely: parse + signature check, runs nothing. | none |
verify <envelope> --repo <clone> |
Owner handshake: re-prove provenance ▸ safety ▸ correctness ▸ fit. --apply merges with credit. |
owner's |
submit <envelope> |
Open a native PR from your fork with the envelope attached, authored by your GitHub identity. | none |
seal <envelope> --repo <clone> |
Decision-first PR seal: identity, a deterministic risk band, tests, provenance. Powers the GitHub Action. | none/owner's |
attest <repo> |
Sign a standard in-toto/DSSE audit attestation — no diff, credits nobody, auditor bound to a GitHub identity. | your own |
verify-attest <file> |
Verify a DSSE attestation independently (works with cosign too). |
none |
label <artifact> |
Print the plain-text confirmation card that rides with an envelope/attestation. | none |
extract <envelope> |
Explode an envelope into envelope.json + contribution.patch — the open form, no crowdcoding needed to read it. |
none |
init |
Stamp the machine-detectable opt-in badge on a repo's README. | none |
analyze and contribute use the council brain (your own LLM); pull and pack are the
AI-free "do it your way" path — you author the diff by hand and crowdcoding just signs and
packages it into an Envelope the owner re-proves exactly the same way.
Quickstart (offline, no key, zero cost)
Everything here runs with no network and no API key — the bundled mock backend is a
deterministic offline stub used by the test suite and CI.
python -m pip install -e .[dev]
crowdcoding --version # crowdcoding 0.1.1
crowdcoding keygen # prints your PUBLIC key; private stays in ~/.crowdcoding/key.pem
python -m pytest -q # 264 passing — the full contribute → verify → credited-merge flow
keygen, pull, pack, inspect, and init need no model and no API key — the whole
do-it-your-way path (edit a clone, seal it, read the result) runs fully offline.
The test suite is the offline proof: it drives two independent mock councils end to end, including tamper-rejection and booby-trap-rejection.
The
mockbackend is a stub for tests/CI — it does not synthesize fixes or grades on its own, socrowdcoding analyze <repo> --backend mockandcrowdcoding contribute <repo> --backend mockboth report "no issues". To produce real analysis or contributions, bring your own model (below). The AI-free commands (pull/pack/inspect/init) do not need a backend at all.
Bring your own model
One OpenAI-compatible backend covers every provider — OpenAI, Azure, Gemini/Anthropic compat endpoints, OpenRouter, and local runtimes (Ollama, LM Studio, llama.cpp, vLLM). Configure it with three environment variables:
export CROWDCODING_BACKEND=openai
export CROWDCODING_BASE_URL=http://localhost:11434/v1 # Ollama (fully local, free)
export CROWDCODING_MODEL=llama3
# export CROWDCODING_API_KEY=... # only if the provider needs one; never logged, only its presence
OpenRouter instead:
export CROWDCODING_BASE_URL=https://openrouter.ai/api/v1
export CROWDCODING_MODEL=anthropic/claude-3.5-sonnet
export CROWDCODING_API_KEY=...
Scout first (optional) — read-only grade + briefing of the top fixable issues, no envelope:
crowdcoding analyze https://github.com/owner/repo # add --json for the machine report
Contributor side — analyze, fix, self-verify, and emit a signed envelope credited to your
verifiable GitHub identity (resolved from the gh CLI + your registered SSH key):
crowdcoding contribute https://github.com/owner/repo --out envelope.zip
It drafts the fixes, then STOPS so you review every diff before anything is sent — nothing
leaves your machine until you act. Prefer to skip the AI? Use the pull → hand-edit → pack
path below; it produces the same signed, GitHub-credited envelope with no model at all.
Owner side — re-prove the envelope against your own clone, then merge with credit:
crowdcoding verify envelope.zip --repo /path/to/local/clone --trust strict
crowdcoding verify envelope.zip --repo /path/to/local/clone --apply
--apply requires --repo to be a local working copy, and refuses if the envelope claims a
GitHub identity that does NOT verify. For each accepted piece it runs git apply and one
git commit authored with the contributor's GitHub no-reply email — so once the owner pushes,
the contributor appears natively in the repo's Contributors — plus (per the target repo's AI
policy) an Assisted-By: crowdcoding/<model> trailer and the envelope's SHA-256. Add --json
to any verify for the full machine-readable report.
Do-it-your-way — pull + pack (no AI required)
Prefer to fix things by hand? Skip the council entirely. pull clones the repo into a workspace
and records the exact base commit; you edit however you like; pack diffs your working tree
against that base and seals the change into the same signed Envelope — which the owner
re-proves with the identical handshake. No model, no API key.
crowdcoding pull https://github.com/owner/repo --dest ./repo # clone + record the base commit
# ... edit files in ./repo by hand ...
crowdcoding pack --workspace ./repo --out envelope.zip # sign + package your manual diff
pack credits your verifiable GitHub identity (resolved from the gh CLI + your registered
SSH signing key — no typed-in name), the same as contribute. The base commit is stored in
./repo/.crowdcoding/base.json and kept out of your diff. pack refuses an empty change set, so
an accidental no-op never ships. Pass --backend only if you want a model to write the
owner-facing briefing — the diff itself is always yours.
Read before you trust — inspect
inspect opens an Envelope and reports the sender, base commit, signature validity, and a
per-piece line count without running anything — no clone, no sandbox, no backend. It is safe
to point at an untrusted envelope: parsing plus a signature check is the whole attack surface.
crowdcoding inspect envelope.zip # add --json for the full report
Exit code is 0 when the signature verifies and 2 when it does not (still listing the pieces),
so CI can gate on a tampered/unsigned envelope.
Opt in — init
init stamps a machine-detectable badge on your repo's README so crawlers can find
"Crowdcoding contributions welcome" and humans can click through. It only edits README.md —
never commits, pushes, or reaches the network — and is idempotent (a second run is a no-op).
crowdcoding init --repo . --url https://github.com/you/your-repo # --url defaults to origin
Trust levels
The owner picks how hard to re-prove each envelope:
--trust |
Provenance (signature) | Safety audit | Sandboxed correctness | Fit (style/license/AI policy) |
|---|---|---|---|---|
strict |
✅ | ✅ | ✅ | ✅ |
trusted |
✅ | ✅ | — | — |
direct |
✅ | — | — | — |
A failed signature is fatal at every level: the envelope is rejected and nothing is applied.
direct accepts on a valid signature alone (confidence 0.5) — use it only for contributors you
already trust.
What the handshake guarantees — and what it doesn't
- Signature = authenticity, not trust. It proves the bytes are unaltered and came from the holder of the stated key. It says nothing about whether the change is safe or good — that is what re-proving is for.
- The sandbox is process isolation + a cleaned environment + a hard timeout, not a container.
It runs the untrusted diff in a throwaway copy of the repo, in a subprocess whose environment is
stripped of
CROWDCODING_*,*_API_KEY,*_TOKEN,*_SECRET,*_PASSWORDvariables, and kills the run on timeout. That contains accidents and casual exfiltration — it is not a defense against a determined attacker. Container/VM hardening is the documented post-MVP step. Never runverifyagainst a working tree you care about; the temp copy is always discarded. - The owner always has the final say. Every stage produces evidence; the verdict
(
accept/needs-changes/reject) and confidence are the owner's to act on. - Secrets are scrubbed from every prompt and from provenance excerpts, and are never logged — only their presence is.
Anti-slop stance
Open-source maintainers are rightly wary of unsolicited AI contributions. Crowdcoding is built to respect that:
- Quality over volume — pieces that don't apply cleanly or don't pass the target's own tests are dropped before they ever reach the owner.
- Owner-gated by construction — nothing merges unless the owner's own tooling re-proves it.
- Always disclosed — accepted merges carry an
Assisted-By:trailer, in line with emerging maintainer AI policies. - Policy-aware — the
fitstage reads the repo'sAGENTS.md/CLAUDE.md/LICENSEand judges the piece against them.
Status
MVP, 264 tests passing. Working today: BYO-model contribute, the AI-free pull/pack path,
verifiable GitHub identity across contributions and audits, signed Envelopes, safe inspect, the
owner handshake with trust levels, credited --apply merges, the reproducible risk seal, the open
format + extract, native PR submit, the maintainer-side GitHub Action, and an MCP server for
envelope intake. On the roadmap (design-stage): a hosted verify App.
License
MIT © 2026 Augusto Bastos.
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 crowdcoding-0.1.1.tar.gz.
File metadata
- Download URL: crowdcoding-0.1.1.tar.gz
- Upload date:
- Size: 116.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12329b0626271d62a18df2d1b968deac1f5cf4e5e6336fc0dbb1033bace322a2
|
|
| MD5 |
8ea794b31d9bd91e14df4b272f9aac57
|
|
| BLAKE2b-256 |
e314539c8b5a7b7a63e6f288c06e68a40fe6c138b48d67a155b49f02ce9b8ff0
|
File details
Details for the file crowdcoding-0.1.1-py3-none-any.whl.
File metadata
- Download URL: crowdcoding-0.1.1-py3-none-any.whl
- Upload date:
- Size: 80.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4c0a7336801bc6d0d700a43783d87560d02577ee0eb39fd411d57f2239b14ebd
|
|
| MD5 |
2ca7faa1e2b3f00d7883ce0bbdcb1806
|
|
| BLAKE2b-256 |
536665de5ab36ac7458b71888e8851bc2d5b58f3fabd69af73c9169925042ae5
|