Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
59 changes: 59 additions & 0 deletions .agents/skills/payjoin-workshop/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
name: payjoin-workshop
description: Explain, teach, implement, customize, and review the payjoin-workshop repository's five BIP 77 checkpoints. Use when someone asks about this workshop, src/workshop/steps.ts, its mock/live drivers, the receiver contribution rule, or how to learn Payjoin Dev Kit through the workshop. Keep work educational and testnet-safe; do not treat this skill as a production wallet audit or permission to use real funds.
---

# Payjoin Workshop

Use this skill as a focused Payjoin workshop and PDK knowledge assistant. The repository demonstrates a BIP 77 Payjoin in a browser with two fixture wallets. It is not a wallet, a Bitcoin node, or proof that a production integration is secure.

## Choose the mode

Identify the user's intent before acting:

- **Answer:** answer a question about Payjoin, PDK, the workshop, a checkpoint, an API call, or a trace event using the repository and relevant references.
- **Implement:** complete one requested checkpoint in `src/workshop/steps.ts`, in order, while preserving the driver contract.
- **Customize:** change a workshop policy or presentation deliberately, then add or update tests for the changed behavior.
- **Debug:** trace a failure from the UI or test to the relevant driver/checkpoint and explain the smallest repair.
- **Test:** add or run a focused test that demonstrates the lesson or guards a changed behavior.
- **Review:** inspect a proposed change for protocol invariants, regression risk, and missing evidence; do not silently implement it unless asked.

Map natural language to the relevant checkpoint or source file. The user does not need to know names such as `receiveAndCheck`. If the request is an implementation request and the target is clear, fill the related part directly. If it is only a question, do not edit files.

## Working workflow

1. Inspect the checkout before editing. Read `README.md`, `src/workshop/steps.ts`, `src/workshop/toolkit.ts`, the driver types, and the tests relevant to the request. Check the current branch and preserve unrelated user changes.
2. Establish the boundary: the workshop teaches the integration seam; the toolkit owns polling, persistence, relay failover, and error conversion; the PDK engine owns Payjoin protocol state and validation; the wallet adapter owns addresses, PSBT construction, signing, ownership queries, and coin policy.
3. Identify the checkpoint's sender/receiver role, expected typestate transition, observable trace events, and failure/fallback behavior. State any assumption about a mock-only demonstration versus a live protocol path. Give the direct answer or implementation mapping before details.
4. Make the smallest scoped change. Follow the TODO comments and existing type names. Keep mock and live drivers on the same `DemoDriver` contract. Do not bypass PDK validation by fabricating a successful result in the live path.
5. Verify proportionally. Prefer mock tests and local checks first. Run `npm run check`, `npm test`, and `npm run build` when dependencies are available. Run live E2E only when the user explicitly requests it; it uses public relay infrastructure and must not be looped.
6. Report what changed, the commands and results that provide evidence, and what remains unverified. A passing mock test proves the demo contract, not mainnet safety or real broadcastability.

## Non-negotiable Payjoin teaching points

- The sender first creates a complete, broadcastable Original PSBT. Payjoin is an improvement on a working payment, not a prerequisite for payment.
- The receiver must check the Original PSBT before contributing: broadcastability, input ownership, replay/previously-seen inputs, and the receiver output.
- The receiver contributes only its own input, applies an explicit fee policy, and signs only its own input.
- The sender verifies the Proposal against the Original PSBT before signing sender inputs.
- Preserve the sender's intended outputs and fee protections. Do not describe input order as ownership proof; Payjoin may randomize input placement.
- Explain the directory/mailbox, OHTTP relay, and HPKE encryption as different components with different jobs. Do not collapse them into “the relay encrypts everything.”
- Use mock mode, regtest, or another non-production fixture while learning. Never request, print, or commit private keys, seed phrases, real wallet exports, or unnecessary raw PSBT secrets.

## Reference routing

Read only the reference needed for the current request:

- [Workshop map](references/workshop-map.md): read for checkpoint selection, source files, expected trace, branches, and the driver seam.
- [Protocol and safety](references/protocol-and-safety.md): read for BIP 77 roles, PDK boundaries, typestate reasoning, and security-sensitive explanations.
- [Evaluation and examples](references/evaluation.md): read when designing tests, evaluating a skill response, or customizing workshop behavior.

## Response shape

For implementation or customization, organize the answer around:

1. **Understanding** — role, checkpoint, and intended behavior.
2. **Change** — files and smallest implementation choice.
3. **Verification** — observed command/test results.
4. **Boundary** — what the result does not prove and the next safe exercise.

For knowledge requests, give the direct answer first and then map it to the relevant function, trace event, or PDK concept. For implementation requests, show the smallest related change and its evidence; do not bury the answer under a simulated classroom dialogue or a large unrelated code dump.
4 changes: 4 additions & 0 deletions .agents/skills/payjoin-workshop/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Payjoin Workshop"
short_description: "Teach and guide the Payjoin workshop"
default_prompt: "Use $payjoin-workshop to answer Payjoin and PDK questions or fill the correct workshop code when I ask, using mock or regtest-safe verification."
68 changes: 68 additions & 0 deletions .agents/skills/payjoin-workshop/references/evaluation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Evaluation and example requests

Use this page when testing whether the skill gives accurate workshop/PDK answers and changes only the requested code.

## Minimum verification

For ordinary workshop implementation, use this order:

```sh
npm run check
npm test
npm run build
```

The mock tests should cover at least:

- the complete trace order;
- input/output arithmetic and fee increase;
- the receiver contribution policy;
- invalid or unpayable amounts;
- forced network/protocol/cancellation failures;
- cancellation of an in-flight session.

If a change alters a policy or trace, update the relevant assertion rather than weakening the test. If dependencies are missing, say so and report the check as not run.

Do not run `PAYJOIN_LIVE_E2E=1 npm test` implicitly. It sends public relay traffic and belongs only in an explicitly requested, one-off integration check after the solution path is complete.

## Good direct evaluation prompts

Use realistic student prompts. The skill should answer questions directly and implement only when the request asks for a change:

1. “What does step 3 protect against, and where is it implemented?”
2. “Can you fill the receiver checks in step 3 and run the relevant tests?”
3. “Can you make the receiver contribute the smallest available coin?”
4. “Why must the Original PSBT be broadcastable before Payjoin?”
5. “What is the difference between the directory server, OHTTP relay, and HPKE?”
6. “Can you make a malformed URI become a readable protocol error?”
7. “Review this proposal-signing callback. Could it sign a sender input?”
8. “Why does mock mode pass while a real counterparty cannot broadcast the finished transaction?”
9. “Can you add a test for an empty receiver wallet without changing the production policy?”
10. “I fell behind. Find the first unfinished checkpoint and tell me what it should do.”

## Expected response qualities

A strong response should:

- accept ordinary student language rather than requiring checkpoint names;
- state the relevant checkpoint or source location before making a change;
- name the sender/receiver role and checkpoint;
- connect the concept to the actual function and existing helper;
- preserve the distinction between mock simulation and live PDK behavior;
- identify relevant tests and run or explicitly decline live E2E;
- call out assumptions and unverified security claims;
- avoid asking for secrets or suggesting mainnet testing.

A weak response usually copies a large PDK example without inspecting the repository, changes `mockDriver.ts` to hide a broken live implementation, treats a passing mock test as cryptographic proof, or skips the sender's final Proposal verification.

## Customization acceptance checklist

Before accepting a workshop customization, confirm:

- the change has a named policy or teaching objective;
- the receiver still contributes only its own selected input;
- the sender's required outputs and fee protections remain understood;
- trace IDs remain compatible unless the UI and tests were intentionally updated;
- tests cover the changed behavior and at least one negative path;
- no real keys, mainnet fixtures, or live relay loops were introduced;
- the final report distinguishes implemented, tested, and unverified behavior.
66 changes: 66 additions & 0 deletions .agents/skills/payjoin-workshop/references/protocol-and-safety.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Protocol and safety context

Use this page when explaining why a workshop call exists or reviewing a protocol-sensitive change. It is a teaching summary, not a replacement for the current BIP or PDK API documentation.

## Mental model

Payjoin makes a transaction collaborative: the sender pays the receiver while the receiver adds one of its own inputs. The resulting transaction has inputs from both parties, improving privacy and allowing receiver-side wallet policies such as consolidation.

For BIP 77, the receiver creates an asynchronous session and publishes a BIP 21 URI. The sender parses the URI, creates and signs an Original PSBT, and posts the encrypted request. The receiver polls, checks it, contributes inputs and outputs according to policy, signs its own input, and posts a Proposal. The sender polls, verifies the Proposal against the Original PSBT, signs its own inputs, and finalizes.

The directory server acts as a mailbox. OHTTP separates the party requesting a resource from the party receiving the request. HPKE protects the protocol payload between the participants. These are separate protocol responsibilities and should be explained separately.

## PDK boundary

The Payjoin Dev Kit is the protocol engine and integration toolkit. It is not the application's complete wallet. The application still supplies or selects:

- wallet addresses and UTXO data;
- Original PSBT creation and wallet signing;
- receiver input-selection policy;
- input/output ownership callbacks;
- persistence and session recovery choices;
- network and relay configuration;
- user-facing fallback, cancellation, and retry behavior.

The workshop's `Toolkit` packages many of these choices so learners can focus on the PDK calls. When teaching production code, make the adapter boundary visible instead of implying that the workshop's fixture wallet is a production wallet.

## Receiver checks

Explain the checks as defenses against malformed payments and wallet probing:

1. **Broadcast suitability:** the Original should be acceptable to the wallet/node's broadcast rules.
2. **Inputs not owned:** the sender must not already be spending receiver-owned outpoints.
3. **Inputs not seen before:** a receiver should track seen inputs or equivalent state to reduce probing and replay risk.
4. **Receiver outputs identified:** the receiver must know which output it owns before constructing its Proposal.

The PDK typestate sequence is pedagogical and safety-relevant: the receiver cannot contribute until the required checks have been completed.

## Signature and fee boundaries

The sender signs the Original before the receiver participates. The receiver's proposal-signing callback must sign only receiver-owned inputs. The sender must verify the returned Proposal before signing sender inputs.

When explaining fees, distinguish:

- the sender's Original fee;
- the Proposal's additional input/transaction cost;
- the receiver's allowed fee range;
- whether the receiver or sender bears the additional fee.

Do not claim that a successful demo trace proves an economically optimal fee policy.

## Version discipline

PDK APIs, bindings, BIP wording, and relay infrastructure can change. Before giving version-specific code:

1. inspect the repository's vendored engine and package metadata;
2. identify the exact binding and version in use;
3. prefer the current official PDK/BIP documentation for new API claims;
4. label workshop-specific helper names separately from public PDK API names.

Useful authoritative starting points:

- [Payjoin V2 / BIP 77](https://payjoin.org/docs/how-it-works/payjoin-v2-bip-77/)
- [Payjoin V1 / BIP 78](https://payjoin.org/docs/how-it-works/payjoin-v1-bip-78/)
- [Payjoin Dev Kit](https://payjoindevkit.org/)
- [rust-payjoin repository](https://github.com/payjoin/rust-payjoin)
- [BIP 77 text](https://github.com/bitcoin/bips/blob/master/bip-0077.md)
49 changes: 49 additions & 0 deletions .agents/skills/payjoin-workshop/references/workshop-map.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Workshop map

Use this page when a learner asks where to work or what a checkpoint is meant to teach.

## Repository contract

The learner-facing integration surface is `src/workshop/steps.ts`. It contains five functions with `TODO(step-N)` markers. The surrounding application is deliberately prewritten so the learner focuses on Payjoin integration rather than browser plumbing.

The important supporting files are:

- `src/workshop/toolkit.ts`: wallet helpers, persistence, polling, relay handling, response conversion, and error types.
- `src/driver/types.ts`: the `DemoDriver`, `DemoSession`, trace events, and failure contract shared by mock and live paths.
- `src/driver/mockDriver.ts`: offline simulation used for fast tests and classroom demonstrations.
- `src/driver/wasmDriver.ts`: live PDK/FFI-backed driver.
- `test/mockDriver.test.ts`: contract tests for event order, arithmetic, contribution policy, and cancellation.
- `README.md`: setup, checkpoint instructions, live/mock boundaries, and Rust follow-up.

## Checkpoints

| Step | Function | Role | Learner concept | Success signal |
| --- | --- | --- | --- | --- |
| 1 | `openReceiverSession` | Receiver | Build and save a BIP 77 receiver session; issue a BIP 21 URI | `session-init`, `uri-issued` |
| 2 | `sendOriginal` | Sender | Parse URI; build/sign Original PSBT; wrap and post it through OHTTP | `uri-parsed`, `original-built`, `original-signed`, `request-sent` |
| 3 | `receiveAndCheck` | Receiver | Poll and pass the receiver's safety checks in order | `request-received`, `checks-passed` |
| 4 | `selectContribution`, `contributeAndPropose` | Receiver | Apply wallet policy; contribute an input; fee-range; sign and post Proposal | `inputs-contributed`, `proposal-signed`, `proposal-sent` |
| 5 | `verifyAndFinalize` | Sender | Poll, re-verify Proposal, sign sender inputs, finalize | `proposal-received`, `proposal-checked`, `payjoin-signed`, `done` |

Implement in order unless the learner deliberately checks out a solved checkpoint or asks for a conceptual explanation. The tags `step-1` through `step-5` are solved milestones; `solutions` contains all five solutions; `main` is the learner skeleton. Do not use a forceful checkout over user edits without explicit permission.

## Expected ownership story

The Original transaction contains sender inputs and a receiver payment output. The Proposal adds a receiver-owned input and adjusts the receiver output to account for the contribution and additional fee. The sender's change remains sender-owned. Input order may be randomized, so the UI's owner coloring is explanatory metadata, not a protocol field.

## Mock versus live

Mock mode is offline and intentionally simulates the shape of the protocol. It is useful for classroom flow, deterministic tests, failure cards, and arithmetic checks. It does not compute real signatures or prove broadcastability.

Live mode exercises the real directory and public OHTTP relay path through the vendored engine. It is opt-in in tests, requires every checkpoint, and may use public volunteer infrastructure. Treat live traffic as a one-off integration check, not a load test.

## Safe customization examples

Good bounded changes include:

- replace `consolidate-smallest` with a clearly named, tested receive policy;
- change trace wording without changing the driver event IDs;
- add a negative test for an invalid amount, empty receiver wallet, cancellation, or failed proposal;
- add a teaching panel that explains one existing trace event.

Changes that require a separate design review include changing fee protection, changing which inputs may be contributed, accepting unchecked proposals, changing persistence semantics, or adding real-wallet fixtures.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ Nothing here is spendable and nothing is broadcast. In live mode the protocol
runs over the real payjo.in directory server and public OHTTP relays; in mock
mode it runs with no network at all.

This repository also includes an AI agent skill in `.agents/skills/payjoin-workshop/`.
It helps an agent explain and implement the workshop's five BIP 77 checkpoints,
while preserving the mock/live driver contract and Payjoin safety boundaries.
The skill is educational and testnet-safe; it is not a production wallet audit.

## Before you start

1. Install Node.js 20 or later (https://nodejs.org).
Expand Down