Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a99153e
feat(cli): discover trusted upstream base without silently using HEAD
daichunghy Oct 10, 2026
b3ed40b
feat(cli): doctor, check, strict checks and receipt integrity validation
daichunghy Oct 10, 2026
4701ad0
fix(hooks): inspect PR creation inputs without blocking ordinary agen…
daichunghy Oct 10, 2026
46ea165
test(ux): cover first-run CLI, strict CI and tamper-detecting receipts
daichunghy Oct 10, 2026
12ae306
fix(ux): smoke-test first-use help and support PowerShell executable …
daichunghy Oct 10, 2026
f9e00d9
docs(product): design progressive CLI workflows with verifiable readi…
daichunghy Oct 10, 2026
761e121
docs: ship polished onboarding and align agent skills, smoke helper, …
daichunghy Oct 10, 2026
ef5ad2c
docs: show the actual published npm alpha and CI badge distinctly fro…
daichunghy Oct 10, 2026
6527abb
fix(ux): require explicit fork base, parse GitLab MR flags, and suppo…
daichunghy Oct 10, 2026
25f69ed
fix(hook): require human-review override and document fork/GitLab safety
daichunghy Oct 10, 2026
367bb34
docs: distinguish nonblocking advisory findings from actual receipt s…
daichunghy Oct 10, 2026
464a9c5
docs: distinguish nonblocking advisory findings from actual receipt s…
daichunghy Oct 10, 2026
72bf7bd
fix(ux): warn on HEAD-only checks and explicit policy revision overrides
daichunghy Oct 10, 2026
9d83564
fix(ux): warn on HEAD-only checks and explicit policy revision overrides
daichunghy Oct 10, 2026
372942e
docs(ux): explain fork-only origin limitation and verify review targe…
daichunghy Oct 10, 2026
15d610a
docs(ux): explain fork-only origin limitation and verify review targe…
daichunghy Oct 10, 2026
aad47bd
docs(ux): explain fork-only origin limitation and verify review targe…
daichunghy Oct 10, 2026
69d7cff
fix(hooks): refuse PR commands hidden inside shell wrappers
daichunghy Oct 10, 2026
11beda1
fix(hooks): refuse PR commands hidden inside shell wrappers
daichunghy Oct 10, 2026
0f539ac
fix(hooks): refuse PR commands hidden inside shell wrappers
daichunghy Oct 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ contribkit is a deterministic contribution preflight. Do not put an LLM in `comp
```sh
npm install
npm run verify
npx contribkit preflight --repo . --base HEAD
node dist/src/cli.js doctor --repo . --base HEAD
node dist/src/cli.js check --repo . --base HEAD
```

The latest documented release is `contribkit@0.1.0-alpha.7`. Release metadata in this
Expand All @@ -27,3 +28,7 @@ plugin catalog or Claude-for-OSS eligibility.
- `--repo` must be a git clone root. Do not walk up to a parent repository.
- Locale-free sorts (code-unit comparator). `evaluatedAt` and `overridden` sit outside the digested receipt body.
- Follow [docs/agent-verification-map.md](docs/agent-verification-map.md) and [docs/agent-evaluation-protocol.md](docs/agent-evaluation-protocol.md) for bounded agent work, acceptance commands and evidence labels.

## UX contract

Use docs/PRODUCT_EXPERIENCE.md and docs/first-use.md to preserve the contributor, maintainer and automation paths. Never let a missing base silently fall back to HEAD. Keep the published npm alpha separate from source-only commands.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@ All notable changes are documented here, newest first. Entries mirror the tagged

## [Unreleased]

- Reworked first-run UX into `doctor` (diagnostic) and `check` (preflight)
with automatic remote-tracking base selection; missing bases now fail
clearly rather than silently using HEAD and skipping committed work.
- Added `--strict` for machine use (needs-human exits 3); made unknown flags,
missing values and conflicting PR-body options fail with explicit errors.
- Added receipt body-digest verification to CLI and MCP `explain`; digest
detects tampering but does not authenticate authorship.
- Hardened Claude PR hooks to inspect only PR-create operations, extracting
inline and body-file evidence without executing the command.
- Improved fork safety by refusing an ambiguous origin/upstream base;
updated GitLab MR flag handling and made hooks deny unresolved human review
until an explicit user override.
- Added end-to-end first-use, hook and packed-package regression cases,
a contributor journey contract and updated onboarding documentation.
Not published in the npm alpha yet.


- Fixed MCP stdio JSON-RPC framing to use newline-delimited messages, bounded
input, correct notification behavior, and regression tests for split frames.
- Compile contribution rules from the trusted diff base by default to prevent
Expand Down
246 changes: 146 additions & 100 deletions README.md

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# contribkit architecture

## Interface layers

- Contributor: `doctor` → `check` → actionable receipt, with no mandatory
configuration or target script execution.
- Maintainer: explicit policy on a trusted Git base, versioned schema and
optional blocking adapters.
- Automation: `--strict`, JSON receipts with body-digest verification,
Claude Code PR hooks and MCP stdio using the same compiler/evaluator.

The command-line interface never falls back to HEAD just to produce an easy
pass. The remote-tracking base is a cached Git ref; users remain responsible
for fetching updates. Clones with both `origin` and `upstream` must specify
an explicit review target instead of incorrectly accepting the fork as
source of the maintainer's rules. GitLab and GitHub CLIs expose different
PR-description and base flags; hook parsing is separated by vendor.

## Processing pipeline

```text
Expand Down
96 changes: 96 additions & 0 deletions docs/PRODUCT_EXPERIENCE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Product experience and readiness contract

Status: working design and internal regression evidence, October 2026.
No independent user study or external pilot has yet validated these flows.

## What problem are we solving?

A coding agent or contributor can create a PR faster than they can understand
the target repository's local rules. The resulting friction is missed issue
references, unrecorded tests, oversize diffs, and review delays. ContribKit
should make the *next required action* clear before the PR exists.

The project must not become another generic test runner, a remote GitHub merge
gate, or an AI code-quality oracle. The deterministic compiler and versioned
receipt remain the technical core.

## Evidence from adjacent products

- pre-commit provides obvious verbs (install, run, try-repo), making the
everyday path easier to discover than its configuration internals.
https://pre-commit.com/
- Lefthook separates install, run and validate from its advanced hook
configuration, reducing commands a newcomer must remember.
https://lefthook.dev/usage/
- Danger JS addresses policies *after* PR creation in CI. ContribKit's
distinctive moment is *before* PR creation, locally and without tokens.
https://danger.systems/js/guides/getting_started
- GitHub CLI accepts --body / --body-file and a selectable --base when creating
PRs. The hook should consume this metadata when available rather than
asking people to type it twice.
https://cli.github.com/manual/gh_pr_create
- MCP stdio requires newline-delimited JSON-RPC. Product usability includes
protocol interoperability and correct error behavior, not just help text.
https://modelcontextprotocol.io/specification/2025-11-25/basic/transports

These sources are **design references**, not evidence that users prefer
ContribKit or that its implementation has external adoption.

## Progressive disclosure: one engine, three entrypoints

1. **Contributor path:** doctor → check → act on findings → create PR.
Default to a discoverable cached remote-tracking base. If absent, print a
specific command and fail rather than producing an unexplained green result.
2. **Maintainer path:** commit optional policy to the trusted base; inspect
the compiled contract; choose blocking adapters explicitly.
3. **Automation and agent path:** JSON receipts, strict CI exit codes, bounded
opt-in test execution, MCP and Claude hooks that intercept PR creation
but not unrelated work.

All three use the same deterministic compile/evaluate functions. The UI
must never redefine statuses or turn unverified external claims into passing
test evidence.

## Acceptance tasks and failure signals

| Task | Evidence required | Incorrect behavior |
| --- | --- | --- |
| New contributor in remote-tracking clone | doctor finds correct origin base | silently compares against HEAD |
| Fork with origin and upstream remotes | prompt for explicit target base | compare fork policy against origin/main |
| GitLab MR CLI | capture --description and --target-branch evidence | treat -b as GitHub PR body |
| Local-only clone | actionable error | blank or green receipt |
| Contributor forgot issue reference | check blocks with a next step | vague failure without PR-body instructions |
| Maintainer-owned file changed | needs-human finding | fake approval or completely invisible |
| CI with pending human review | strict exit 3 | exit 0 incorrectly treated as ready |
| Multiple adapter commands | explicit opt-in, individual exit statuses | first command only |
| Newcomer types invalid flag | clear error exit 2 | typo silently ignored |
| User alters receipt JSON | explain refuses digest mismatch | prints forged pass |
| Claude runs a non-PR shell command | hook ignores without compiling repo | unrelated command denied |
| Claude creates PR through CLI/MCP | hook examines body and correct base | bypass or only reads empty PR body |
| Hook sees needs-human | block until explicit override | open PR as if human had approved |
| npm consumer installs packed CLI | clean-room commands load | source-only assumptions in released package |
| Dependency security review | vulnerable versions replaced under tests | upgrade every major without compatibility proof |

## Design principles

- **No silent green:** lack of a base, an empty diff and a needs-human result
are never presented as demonstrated PR readiness.
- **No surprise execution:** compile, doctor and check are passive unless
--run-tests is explicit; tests may still execute target code.
- **Explain from evidence:** findings cite the originating rule or file and
an action; receipts stay machine-readable and separately verifiable.
- **Compatible by default:** keep legacy needs-human status unless --strict
opts into CI-safe nonzero exit.
- **Risk at edges:** limit effectful hook/MCP calls; preserve a non-networked
deterministic compiler.
- **No fake market validation:** pilot, Windows/macOS shells, large monorepos,
GitLab behavior and private repositories still need real user evidence.

## Readiness gates still not met

Do not claim production readiness until a human maintainer independently
reproduces the documented workflow in real repositories, at least one
non-author contributor completes a PR preflight without coaching, an external
pilot reports actual decisions changed by the receipt, and CI/security/
platform acceptance is documented. In particular, npm publication requires
owner authorization and registry-level verification separate from GitHub CI.
17 changes: 17 additions & 0 deletions docs/PRODUCT_SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,23 @@ that code is correct, safe, human-written, or merge-worthy.
- Unknown or conflicting requirements remain visible as `needs-human` rather
than becoming a guessed block.

## First-use experience

The primary interface is progressive: `doctor` checks that an appropriate
review base exists; `check` runs a non-executing preflight and explains
findings; `preflight`, `compile`, `explain`, MCP and Claude hooks expose
advanced surfaces without changing the same deterministic core.

Without explicit `--base`, `check` first tries cached origin/HEAD,
origin/main, then origin/master, and errors if no remote-tracking ref exists.
Neither a clean working tree nor an unresolved human review may be described
as proof of PR readiness. CI users can opt into `--strict` (needs-human exits
3); the legacy default remains 0 for needs-human for compatibility.

An explain step verifies the receipt's digested body, but SHA-256 does not
authenticate a receipt. Hook events unrelated to PR creation do not trigger
preflight. No code from a target repository is run without `--run-tests`.

## v0.1 scope

The first release covers contribution guidance extraction, issue linkage,
Expand Down
11 changes: 11 additions & 0 deletions docs/THREAT_MODEL.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@
| T15 | A target test ignores SIGTERM and keeps running indefinitely | Bound execution time, escalate to SIGKILL and mark timeout with nonzero exit code 124. |
| T16 | MCP clients cannot connect due to HTTP-style framing over stdio | Use newline-delimited JSON-RPC input and output with frame limits and no notification response. |

| T17 | A first-time user silently compares against HEAD and misses committed changes | Use an explicit base or only discover a remote-tracking base; fail with a remediation when unavailable. |
| T18 | A malformed or mistyped CLI flag is silently ignored | Validate per-command options, missing values and mutually exclusive PR body inputs. |
| T19 | A tampered receipt is explained as passing | Verify digest against the current receipt body before explaining it; do not claim signature authenticity. |
| T20 | Claude hook blocks ordinary Bash activity or misses available PR text | Inspect tool name and PR-creation argv without executing it; read explicit body files with size limits. |

| T21 | A fork compares against its own origin instead of the target upstream policy | Detect origin+upstream ambiguity and require an explicit target ref; never guess. |
| T22 | GitLab MR CLI flags are interpreted using GitHub CLI semantics | Parse glab --description/-d and --target-branch/-b separately from gh PR flags. |
| T23 | Hook permits PR creation on needs-human without recorded human decision | Treat needs-human as unresolved and deny PR creation unless explicitly overridden. |

| T24 | A nested shell wrapper launches a PR command without the handler recognizing an argv triple | Refuse statically uninspectable sh/bash/pwsh wrapped PR commands; the hook is still best-effort, not a merge gate. |

## Non-claims

We do not claim memory-safe parsing of every CODEOWNERS dialect, or that a `pass` receipt means the PR will be merged.
Loading
Loading