Skip to main content

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

crowdcoding — trusted contributions to any repo

tests python license status

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 mock backend is a stub for tests/CI — it does not synthesize fixes or grades on its own, so crowdcoding analyze <repo> --backend mock and crowdcoding contribute <repo> --backend mock both 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, *_PASSWORD variables, 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 run verify against 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 fit stage reads the repo's AGENTS.md / CLAUDE.md / LICENSE and 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


Download files

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

Source Distribution

crowdcoding-0.1.1.tar.gz (116.9 kB view details)

Uploaded Source

Built Distribution

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

crowdcoding-0.1.1-py3-none-any.whl (80.1 kB view details)

Uploaded Python 3

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

Hashes for crowdcoding-0.1.1.tar.gz
Algorithm Hash digest
SHA256 12329b0626271d62a18df2d1b968deac1f5cf4e5e6336fc0dbb1033bace322a2
MD5 8ea794b31d9bd91e14df4b272f9aac57
BLAKE2b-256 e314539c8b5a7b7a63e6f288c06e68a40fe6c138b48d67a155b49f02ce9b8ff0

See more details on using hashes here.

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

Hashes for crowdcoding-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4c0a7336801bc6d0d700a43783d87560d02577ee0eb39fd411d57f2239b14ebd
MD5 2ca7faa1e2b3f00d7883ce0bbdcb1806
BLAKE2b-256 536665de5ab36ac7458b71888e8851bc2d5b58f3fabd69af73c9169925042ae5

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