본문으로 건너뛰기
cccskills
무료GitHub에 공개

contribute

Prepare an outside contribution to Pulp or Forge that a maintainer can land with minimal rework — routing (Core vs Forge), local build and test on a plain Mac, the checks that are worth running without Shipyard/Tart/VMs, and the handoff format. Use when contributing without write access or without the maintainer CI fleet.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(2)

  • SKILL.md14.2 KB
  • SUBMIT-PROMPT.md3.1 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Contributing to Pulp / Forge without the maintainer setup

You do not need Shipyard, Tart, VMs, self-hosted runners, or write access. Those are maintainer infrastructure. Your job is a clean, tested, well-scoped change plus an honest account of what you could not verify. A maintainer takes it from there.

Works the same under Claude Code and Codex — this file is the shared source of truth (.agents/skills/), not a per-tool doc.

The one rule that saves the most rework

Say what you did not do. A contribution that fixes one thing and clearly lists three unverified things is far more useful than one that implies everything was checked. The maintainer's expensive step is discovering an unstated gap after merge. Write the gaps down and you are done; hide them and you cost a debugging session.


1. Where does the change belong?

ChangeRepo
DSP, core/**, format adapters, runtime, view/state layersPulp (Core SDK)
Anything any Pulp plugin would wantPulp
Generating plugins — Forge's UI, templates, catalog, workflowForge
Fixing a bug you hit while building with Forge, but the bug is in core/**Pulp

That last row is the common case and the easy one to get wrong. If you found it from the plugin side but the defect lives in the shared layer, it belongs in Pulp, and it should be split out from your product work.

Split by concern, not by session. If one branch contains two unrelated core fixes plus a feature, prepare them as separate patches in dependency order and say which are independent. Independent bug fixes land fast; anything that changes how something sounds gets scrutinized, and shouldn't hold them up.

2. Never touch version files

Do not edit CMakeLists.txt VERSION, .claude-plugin/plugin.json, marketplace.json, or CHANGELOG.md.

Pulp assigns versions after merge (version-at-land) from the diff. A contributor-side bump only creates a conflict that makes the PR obsolete — it does not help. Same for changelog entries: they are regenerated.

3. Build and test locally

cmake -S . -B build-tests -DCMAKE_BUILD_TYPE=Release -DPULP_BUILD_TESTS=ON \
  -DPULP_ENABLE_GPU=ON
cmake --build build-tests -j"$(( $(sysctl -n hw.ncpu) / 2 ))" --target <your-test-targets>
ctest --test-dir build-tests --output-on-failure -R "<pattern>"

Release, not Debug — a Debug build of a GPU/JS UI is dramatically slower and will mislead you into thinking you caused a performance regression.

A share of the cores, not all of them: a full-core build starves everything else on the machine, including whatever you are about to run the tests against. A lint (build_parallelism_guard.py) enforces this across the repo, so a whole-machine -j$(sysctl -n hw.ncpu) copied from anywhere will fail CI.

Add -DPULP_ENABLE_GPU=ON for anything touching view, canvas, render, or an imported design — without it the GPU paths are not built and your tests may not exist. A first configure also fetches external SDKs (VST3, Skia prebuilts), so budget time for it and do not take the first run's duration as normal.

Python 3.11+ is worth installing before you start, not after a gate confuses you — macOS ships 3.9, and several checks misreport on it:

brew install python@3.12 && python3.12 -m pip install --user diff-cover
# then run the check under it:
PYTHON=python3.12 tools/scripts/contributor_check.sh <targets>

If your Mac exports SDKROOT pointing at a CommandLineTools SDK, the build can fail on missing std::jthread. Pass an explicit modern SDK: -DCMAKE_OSX_SYSROOT=macosx26.2. This is a local environment workaround, not a change to make in the repo.

Formatting: only the lines you touched, never the whole file

The tree does not round-trip under .clang-format and no clang-format version makes it: measured 2026-09-14, clang-format 21 (Xcode, CommandLineTools and Homebrew llvm@21 produce byte-identical output) reflows 3,743 of the 4,415 committed C++ files, and clang-format 19 differs from 21 on two. Existing debt is grandfathered; the only check is diff-scoped — the pre-push hook and the Format (changed lines) workflow run it advisory on the lines you touched. A whole-file clang-format -i (or pulp fmt on an existing file) yields hundreds of unrelated changed lines that a reviewer must wade through and no gate asked for. The alternative — hand-matching the surrounding style — is what people fall back to, and it is slow and error-prone.

Use the diff-scoped wrapper instead. It formats only the hunks that differ from a base ref (--lines= per hunk), formats a brand-new file whole, and finds a clang-format 21 on its own from Homebrew llvm@21, the Xcode toolchain, or CommandLineTools:

tools/scripts/format_changed.sh              # rewrite touched lines vs origin/main
tools/scripts/format_changed.sh --check      # report only; exit 1 if any touched line would change
tools/scripts/format_changed.sh --base main  # different base

Exit 3 with an install hint means no clang-format was found (brew install llvm@21, or xcode-select --install); it is labelled INFRASTRUCTURE and the pre-push hook reports it as a skip, never as a formatting failure. A different major prints a warning and still runs — output differs on a handful of files, not in kind. CI pins clang-format==21.1.8 from PyPI, measured byte-identical to the Xcode, CommandLineTools and Homebrew 21 binaries.

4. Tests ship with the fix — and must fail without it

Non-negotiable in this repo. For every fix, add a test and prove it fails when the fix is reverted. Revert the change, rebuild, watch it fail, restore. Then say so in the handoff — "confirmed failing without the fix" is the single most credible sentence you can write.

"It compiles" and "CI was green" are not tests.

Register a new test in test/cmake/<owner>_tests.cmake, never in test/CMakeLists.txt. The top-level file is a frozen include hub and adding a registration there trips the hotspot gate — the obvious place is the wrong one.

5. Run the contributor check

tools/scripts/contributor_check.sh                    # whole diff vs origin/main
tools/scripts/contributor_check.sh pulp-test-<name>   # also measure diff coverage

It runs only what is meaningful on a plain Mac: version-file hygiene, that tests accompany source, a size/structure review, the sub-second repo gates, and diff coverage. It never needs Shipyard, Tart, or a VM. Its own self-tests are tools/scripts/test_contributor_check.sh.

A check it cannot run is not a failure — it is a line in your handoff. The script prints those together at the end, ready to paste. Do not bypass a gate silently.

Two environment facts worth knowing before you read its output:

  • Python 3.11+. Parts of gates.sh need tomllib and unittest's enterContext, neither of which exists in the 3.9 macOS ships. On stock Python you will see deps-audit self-tests: failing — that is the interpreter, not your change. The script says so rather than blaming your work, but install 3.11+ if you want a real answer. Skill-sync and version-bump — the two gates that most often send a PR back — do run correctly on 3.9.
  • Coverage is opt-in. Pass your test target(s) to measure it. With no target the whole-tree coverage build takes ~30 minutes, so the script skips it and tells you rather than appearing to hang. It also skips automatically when your diff contains no C/C++ — there is nothing to cover. A coverage run that was skipped rather than measured (the host was starved, or it is a maintainer CI host that refuses local builds) reports NOT CHECKED, never a pass or a fail.

Path-based gates can fire on files you barely touched

Some gates key off paths, not semantics. Touching widget_bridge.hpp demands a test/test_widget_bridge*.cpp change and compat-doc updates even if you only added a private declaration. If your tests genuinely belong elsewhere (beside existing coverage for the same behavior), leave them there and say so — the maintainer decides whether the gate is meant literally. Do not scatter tests to appease a path match.

Adding a file under tools/scripts/ or a new skill also has an inventory to regenerate — python3 tools/scripts/pulp_tooling_disposition.py --write, which needs PyYAML and then an explicit disposition for the new entry. contributor_check.sh does not catch this one; the Vellum freeze CI check does.

When a gate is genuinely not meant for your change

Some gates are satisfied by a commit trailer stating why, not by contorting the change. This is a sanctioned, audited escape hatch — it lives in git history where a reviewer sees it — not a bypass:

Skill-Update: skip skill=<name> reason="..."
Version-Bump: skip reason="..."
Config-Doc: skip reason="..."

Put one on the tip commit, with a real reason. If you believe a path-based gate is firing on a file you barely touched, this is how you say so — and then the maintainer can agree or disagree with a specific claim rather than guessing.

Do not reach for a trailer to silence a gate you simply have not addressed. "I added the test somewhere the gate does not look, here is where" is a reason. "It was failing" is not.

Comments: no issue numbers, no phase or PR breadcrumbs

docs_noise_lint runs in the maintainer's pre-push and in CI, but not in gates.sh — so nothing you run locally will catch this, and agents write exactly what it forbids by default. In source comments and test tags, do not write (Phase 2), slice 3 of, fixes #1234, or [issue-NNN]-style Catch2 tags. Write what the code does; the narrative belongs in the commit message.

git diff origin/main | grep -nE '^\+.*(//|#|\*).*(#[0-9]{3,}|[Pp]hase [0-9]|slice [0-9])'

If you touch the check script itself

It runs on two very different shells: bash 3.2 on a contributor's macOS, and bash 5 on Linux CI. They fail in opposite directions, so passing locally proves little.

The concrete trap: ${#arr[@]:-0} is a bad substitution in bash 5 but is accepted silently by 3.2. Arrays here are all explicitly initialized, so plain ${#arr[@]} is right on both. mapfile is the mirror image — bash 4+ only, so it breaks on macOS instead.

bash -n catches neither; both are runtime. The self-tests grep for the known bad form, because macOS cannot execute its way into the failure.

6. Structure — keep it landable

Before handing off:

  • No file you touched should cross ~1000 LOC without a reason you can state.
  • A new core/** source file with no matching test is a red flag.
  • Extract duplicated logic rather than copying it — if you fixed the same bug in two files, that is a sign the helper should be shared, and reviewers will ask.
  • Prefer several small commits with real messages over one large one.

7. Hand it off

If you have write access

Push the branch, then gh pr create. Do not run shipyard pr, and do not arm auto-merge — that is the maintainer's call.

If the PR opens but required checks show MISSING rather than pending, the workflows did not run on its head; say so rather than waiting it out. An App-opened PR does trigger pull_request workflows like any other: across the fleet's last 180 pull requests (165 opened by shipyard-local[bot]), every one targeting main had pull_request runs on its head. A missing check means one of three things, and the CI skill's slow/stuck-PR steps tell them apart:

  • the trigger refused (a base other than main, a path filter), so no run exists on the head;
  • a run exists on the head but sits pending with zero jobs, because a superseded run holds the workflow's concurrency group (case 1b): the check reads MISSING because its job was never created;
  • a run was cancelled.

The fix is never a workflow_dispatch, nor shipyard rescue, which dispatches one: a dispatch checks out the branch tip rather than the merge ref.

If you have READ access only (the common case)

You cannot push a branch. Two good options:

# format-patch series — reviewable, and `git am`-able in order
git format-patch --stdout <base>..HEAD > 01-my-change.patch

# or a bundle carrying the real commits
git bundle create my-work.bundle <base>..HEAD

Record the exact base commit you built on, verify your patches apply cleanly to it, and say so. A maintainer can then reproduce your branch exactly.

Alternatively fork the repo and open a PR from the fork — a normal PR, but note that some workflows behave differently for forks.

The handoff document

Ship a short README.md/HANDOFF.md alongside the patches with:

  1. Base commit and how to apply
  2. Suggested split — which patches are independent, which order
  3. What each change fixes, and how the defect was found
  4. Verification — test suites run, with results; and for each test, that it was confirmed failing without the fix
  5. What you could not do — access, gates not run, platforms not built, hosts not verified, anything judged by ear rather than measured
  6. Recommendations — anything you consider a starting point rather than a finished surface, and known rough edges in what you added
  7. Provenance — one line: that the work is yours and you are contributing it under the repo's MIT license, and the origin of anything that is not yours (adapted from a reference, generated, copied from another project — with its license). Pulp is MIT and public; a maintainer cannot land code whose licensing is unstated. git commit -s (Signed-off-by) is a fine way to say the first half.

That structure is what makes a contribution cheap to land. Sections 4 and 5 matter most.

What you are NOT expected to do

Linux or Windows builds · DAW/host verification · sanitizers · multi-platform validation · shipyard pr · merge-queue interaction · version bumps · changelog edits · running the full ~16k-test suite.

State plainly that you did not do them. That is the correct outcome, not a shortfall.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

aax

무료

Optional AAX support for Pulp, including developer-supplied Avid SDK setup, CMake enablement, DigiShell/AAX Validator workflows, and local AAX builds on macOS or Windows.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Generous-Corp/pulp222026년 10월 19일 업데이트

Configure, implement, and test Pulp's optional desktop Ableton Link tempo-sync adapter while preserving the developer-supplied SDK, licensing, realtime, latency-compensation, and no-install boundaries.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Generous-Corp/pulp222026년 10월 19일 업데이트

Maintain Pulp's installed design-time agent capability manifest and public-surface ledger. Use when adding, removing, renaming, or materially changing public audio, MIDI, signal, timebase, or sequence APIs; registering a new algorithm for generators; changing capability support or deprecation state; or repairing agent-capabilities freshness, schema, fingerprint, tombstone, or installed-SDK tests.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Generous-Corp/pulp222026년 10월 19일 업데이트

android

무료

Android platform development for Pulp — NDK cross-compilation, Oboe audio, Dawn/Skia GPU rendering, JNI bridge, touch interaction, emulator workflows, and end-to-end smoke validation. Covers build, deploy, debug, and the gotchas discovered during bringup.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Generous-Corp/pulp222026년 10월 19일 업데이트

ara

무료

Optional ARA support for Pulp, including developer-supplied ARA SDK setup, CMake enablement, adapter companion APIs, validation, and ARA-aware plugin implementation guidance.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Generous-Corp/pulp222026년 10월 19일 업데이트

The measurement surface for ALL Pulp DSP and audio-pipeline work — read it BEFORE writing or gating DSP, not only when something already sounds wrong. Covers the C++ harness (signal generators, metrics, assertions, RenderScenario, contracts), the offline Audio Doctor (magnitude/frequency response, THD/THD+N, phase/group delay), and their Python sibling the Audio Quality Lab (tools/audio/quality-lab — null residual + alignment, LTAS log-spectral distance, spectral flux/centroid, HNR, Theil-Sen drift slope, Kaiser-sinc resampling, license-guarded corpus, regression-net ratchet). TRIGGER on AUTHORING work — "build/design an oscillator/filter/synth/effect", "add a DSP module", "what should the acceptance gate be", "how do I measure aliasing / anti-aliasing / alias floor", "null against a reference", "is this DSP correct", "choose a tolerance", "golden/regression corpus for audio", "measure drift or jitter", "A/B two renders" — AND on DEBUGGING work — "is there sound / no audio / I hear nothing", "does this filter/compressor/synth/delay produce the right signal", "prove the DSP / prove the contract", "measure the frequency response", "what's the THD / is it distorting", "what's the group delay / phase response / measured latency", "magnitude response curve", "render a test tone and assert", "audio regression", "64-frame works but 128 is silent", "sample-rate change pitch-shifted it", "describe what's in this buffer", "audio doctor", "compare before/after a DSP refactor". Reach for this BEFORE hand-rolling any FFT, null test, alias measurement, pitch tracker, or golden-render script — most of it already exists in one of the two lanes. Test/tool layer over HeadlessHost — deterministic, no audio device, no speakers. Off the realtime thread entirely.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

Generous-Corp/pulp222026년 10월 19일 업데이트

Generous-Corp의 스킬 모두 보기

이 스킬의 문제 신고