Skip to content

feat: Clerk CLI Skill#126

Open
wyattjoh wants to merge 13 commits intomainfrom
feat/clerk-cli-skill-pinned
Open

feat: Clerk CLI Skill#126
wyattjoh wants to merge 13 commits intomainfrom
feat/clerk-cli-skill-pinned

Conversation

@wyattjoh
Copy link
Copy Markdown
Contributor

@wyattjoh wyattjoh commented Apr 7, 2026

Summary

Bundles the clerk skill into the CLI binary, pins it to the version of the binary that installed it, and teaches the skill how to invoke clerk using whatever runner the project prefers.

How it's bundled

  • Markdown files at <repo-root>/skills/clerk/ are pulled into skills.ts as text imports (import md from "./SKILL.md" with { type: "text" }). These resolve live during bun run dev and get embedded by bun build --compile, so the skill content always matches the binary running it.
  • At install time, the staged bundle is handed to <runner> skills add <tmpdir> --copy. --copy is required: the default symlink mode would point each agent's skill dir at the temp dir we delete right after the install.
  • skills-lock.json records the install with sourceType: "local", correctly excluding it from skills update. The skill can only change when the CLI is upgraded.

How it pins

  • Every asset is piped through a new renderSkillVersionPlaceholder(content, version) helper that substitutes {{CLI_VERSION}} at staging time. Release builds pin to the shipped version; dev builds (0.0.0-dev) resolve to latest.
  • DEV_CLI_VERSION and resolveCliVersion() live in a new lib/version.ts so the three sites that care about the dev sentinel (the --version fallback, the skill templater, and scripts/build.ts) share one source of truth and can't drift.

How the skill invokes clerk

A new "Invoking the CLI" section in SKILL.md teaches Claude to prefer a globally installed clerk binary first, and fall back to a pinned bunx / npx -y / pnpm dlx / yarn dlx in lockfile-preferred order. Mirrors the CLI's own preferredRunner logic.

Skill correctness

  • Removes a wrong claim that clerk init --prompt prints a framework-specific integration guide. It prints a short agent handoff telling the agent to run clerk init -y.
  • Resyncs the skill against the current CLI surface: adds init, apps create, open, completion, and skill install to the Core commands table; adds --destructive to config patch/put; strengthens the Prerequisites section so clerk doctor --json is the mandatory session-start check; documents agent-mode behavior for apps create and clerk open.
  • Adds --name (with --starter) to the init row and --secret-key to the api row in the Core commands table, and corrects the clerk api ls --platform apps example (dropped an erroneous --).
  • Repositions clerk <command> --help as the source of truth for flags so the skill stays a hint rather than a spec, reducing drift surface.

Skill rename

The bundled skill is named clerk (directory: skills/clerk/, frontmatter name: clerk). CLI-level identifiers that ship to user state (macOS KEYCHAIN_SERVICE, envPaths config/cache dir) keep the clerk-cli name to avoid orphaning existing installs on upgrade.

Installer continuity

  • Upstream clerk/skills continues to install via default symlink mode; the two installer calls share runner detection and fail independently.
  • buildSkillsArgs gains a copy parameter and threads it through runSkillsAdd so only the clerk skill install gets --copy.

Stacked on #125.

Test plan

  • bun run test passes (unit tests cover buildSkillsArgs --copy, renderSkillVersionPlaceholder edge cases, and withStagedClerkSkill staging + cleanup + version rendering)
  • Manual: run clerk init in a sandbox; confirm clerk and framework-pattern installs both succeed; check skills-lock.json records clerk with sourceType: "local"
  • Manual: confirm .claude/skills/clerk/ contains real files (not a broken symlink) after init
  • Manual: confirm the installed SKILL.md no longer contains the literal {{CLI_VERSION}} after install

@wyattjoh
Copy link
Copy Markdown
Contributor Author

wyattjoh commented Apr 7, 2026

@wyattjoh wyattjoh force-pushed the feat/clerk-cli-skill-pinned branch from 40b1139 to 2b430c5 Compare April 7, 2026 19:40
@wyattjoh wyattjoh force-pushed the feat/lib-non-empty-array branch from 26405f7 to 1e94859 Compare April 7, 2026 19:40
@wyattjoh wyattjoh force-pushed the feat/clerk-cli-skill-pinned branch from 2b430c5 to bd75724 Compare April 7, 2026 20:23
@wyattjoh wyattjoh force-pushed the feat/lib-non-empty-array branch from 1e94859 to 670617f Compare April 7, 2026 20:23
@wyattjoh wyattjoh force-pushed the feat/clerk-cli-skill-pinned branch from bd75724 to 510829c Compare April 7, 2026 21:58
@wyattjoh wyattjoh force-pushed the feat/lib-non-empty-array branch 2 times, most recently from 10da1db to a4185bb Compare April 8, 2026 21:39
@wyattjoh wyattjoh force-pushed the feat/clerk-cli-skill-pinned branch 2 times, most recently from dae4ecc to 75f79d4 Compare April 9, 2026 20:23
@wyattjoh wyattjoh force-pushed the feat/lib-non-empty-array branch 2 times, most recently from a45b262 to c95a429 Compare April 9, 2026 22:54
@wyattjoh wyattjoh force-pushed the feat/clerk-cli-skill-pinned branch from 75f79d4 to 2bc5f72 Compare April 9, 2026 22:54
@wyattjoh wyattjoh force-pushed the feat/lib-non-empty-array branch from c95a429 to 79d474f Compare April 11, 2026 06:48
@wyattjoh wyattjoh force-pushed the feat/clerk-cli-skill-pinned branch from 2bc5f72 to c52bc3f Compare April 11, 2026 06:48
@wyattjoh wyattjoh force-pushed the feat/lib-non-empty-array branch from 79d474f to 08653a1 Compare April 11, 2026 06:54
@wyattjoh wyattjoh force-pushed the feat/clerk-cli-skill-pinned branch from c52bc3f to 27b5058 Compare April 11, 2026 06:54
@wyattjoh wyattjoh force-pushed the feat/lib-non-empty-array branch from 08653a1 to a8903e7 Compare April 13, 2026 20:01
@wyattjoh wyattjoh force-pushed the feat/clerk-cli-skill-pinned branch 2 times, most recently from f0d314f to 8e087a7 Compare April 13, 2026 22:49
@wyattjoh wyattjoh force-pushed the feat/lib-non-empty-array branch from a8903e7 to 190c5d5 Compare April 13, 2026 22:49
@wyattjoh wyattjoh force-pushed the feat/clerk-cli-skill-pinned branch from 8e087a7 to 13e75ab Compare April 13, 2026 23:20
@wyattjoh wyattjoh force-pushed the feat/lib-non-empty-array branch from 190c5d5 to 09c9f9b Compare April 13, 2026 23:20
@wyattjoh wyattjoh force-pushed the feat/clerk-cli-skill-pinned branch from 13e75ab to 7154722 Compare April 14, 2026 18:50
@wyattjoh wyattjoh changed the title feat(init): version-pinned clerk-cli skill installer feat(init): bundle clerk-cli skill into the binary Apr 14, 2026
@wyattjoh wyattjoh force-pushed the feat/lib-non-empty-array branch from 09c9f9b to 59ca3db Compare April 14, 2026 18:56
@wyattjoh wyattjoh force-pushed the feat/clerk-cli-skill-pinned branch from 97cadfd to 9255b9a Compare April 15, 2026 16:50
@wyattjoh wyattjoh force-pushed the feat/lib-non-empty-array branch from c7f94fa to 78613e5 Compare April 15, 2026 20:06
@wyattjoh wyattjoh force-pushed the feat/clerk-cli-skill-pinned branch from 998207f to 71e2f9f Compare April 15, 2026 20:06
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 15, 2026

🦋 Changeset detected

Latest commit: 61a2b63

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
clerk Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@wyattjoh wyattjoh force-pushed the feat/clerk-cli-skill-pinned branch from 71e2f9f to 8078ef6 Compare April 15, 2026 21:13
@wyattjoh wyattjoh force-pushed the feat/lib-non-empty-array branch from 78613e5 to 5ae8ed6 Compare April 15, 2026 21:13
@clerk clerk deleted a comment from changeset-bot bot Apr 15, 2026
@wyattjoh wyattjoh force-pushed the feat/lib-non-empty-array branch from 5ae8ed6 to f9c2e28 Compare April 15, 2026 22:23
@wyattjoh wyattjoh force-pushed the feat/clerk-cli-skill-pinned branch from 8078ef6 to 7a2025d Compare April 15, 2026 22:23
Base automatically changed from feat/lib-non-empty-array to main April 15, 2026 22:38
@wyattjoh wyattjoh force-pushed the feat/clerk-cli-skill-pinned branch from 7a2025d to 61ddd30 Compare April 15, 2026 22:48
@wyattjoh wyattjoh marked this pull request as ready for review April 15, 2026 22:48
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 15, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 95c37677-a5ff-44c4-993f-eafe22b41639

📥 Commits

Reviewing files that changed from the base of the PR and between 9c7d911 and 61a2b63.

📒 Files selected for processing (22)
  • .changeset/clerk-skill.md
  • README.md
  • packages/cli-core/src/cli-program.ts
  • packages/cli-core/src/commands/init/README.md
  • packages/cli-core/src/commands/init/bootstrap-registry.ts
  • packages/cli-core/src/commands/init/bootstrap.ts
  • packages/cli-core/src/commands/init/context.ts
  • packages/cli-core/src/commands/init/frameworks/types.ts
  • packages/cli-core/src/commands/init/index.ts
  • packages/cli-core/src/commands/init/skills.test.ts
  • packages/cli-core/src/commands/init/skills.ts
  • packages/cli-core/src/commands/skill/README.md
  • packages/cli-core/src/commands/skill/install.test.ts
  • packages/cli-core/src/commands/skill/install.ts
  • packages/cli-core/src/lib/package-manager.ts
  • packages/cli-core/src/lib/version.ts
  • scripts/build.ts
  • scripts/tsconfig.json
  • skills/clerk/SKILL.md
  • skills/clerk/references/agent-mode.md
  • skills/clerk/references/auth.md
  • skills/clerk/references/recipes.md
💤 Files with no reviewable changes (1)
  • packages/cli-core/src/commands/init/skills.test.ts
✅ Files skipped from review due to trivial changes (11)
  • .changeset/clerk-skill.md
  • scripts/tsconfig.json
  • packages/cli-core/src/commands/init/index.ts
  • packages/cli-core/src/lib/package-manager.ts
  • packages/cli-core/src/lib/version.ts
  • packages/cli-core/src/cli-program.ts
  • packages/cli-core/src/commands/init/README.md
  • packages/cli-core/src/commands/init/bootstrap.ts
  • skills/clerk/references/auth.md
  • packages/cli-core/src/commands/skill/README.md
  • skills/clerk/references/recipes.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • scripts/build.ts
  • packages/cli-core/src/commands/init/context.ts
  • packages/cli-core/src/commands/init/frameworks/types.ts
  • packages/cli-core/src/commands/init/bootstrap-registry.ts

📝 Walkthrough

Walkthrough

Adds a new top-level clerk skill install command that stages the bundled Clerk skill assets, resolves a package-runner, and delegates installation to the external skills CLI (interactive and unattended flows supported). Introduces centralized lib/package-manager.ts and lib/version.ts modules for package-manager enums and CLI version resolution. Refactors init to install the bundled Clerk skill separately from upstream framework-pattern skills, adds tests for skill staging/arg-building, and includes extensive Clerk skill documentation and README/CLI help updates.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title 'feat: Clerk CLI Skill' clearly and concisely describes the main feature added in the changeset: bundling and integrating a clerk skill into the CLI binary.
Description check ✅ Passed The pull request description is comprehensive and directly related to the changeset, explaining how the skill is bundled, pinned to CLI version, invokes the CLI, and maintains installer continuity.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@wyattjoh wyattjoh changed the title feat(init): bundle and pin the clerk-cli skill to the CLI binary feat(init): bundle and pin the clerk skill to the CLI binary Apr 15, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/cli-core/src/commands/init/skills.ts (1)

60-90: ⚠️ Potential issue | 🔴 Critical

Don’t reinstall clerk from the upstream source after staging the bundled skill.

installClerkSkillCore() already installs a local skill named clerk. upstreamSkills still contains "clerk", so the second runSkillsAdd() call asks the skills CLI to install another clerk from clerk/skills. That can replace the pinned local install or fail on a duplicate-name conflict, which defeats this PR’s core bundling/pinning behavior.

Suggested fix
-  const upstreamSkills = resolveUpstreamSkills(frameworkDep);
+  const upstreamSkills = resolveUpstreamSkills(frameworkDep).filter(
+    (skill) => skill !== "clerk",
+  );
   const skillList = ["clerk", ...upstreamSkills].join(", ");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli-core/src/commands/init/skills.ts` around lines 60 - 90,
upstreamSkills includes "clerk" which causes runSkillsAdd to reinstall the
staged local skill; filter out "clerk" after computing upstreamSkills and before
calling runSkillsAdd (e.g. const upstreamToInstall = upstreamSkills.filter(s =>
s !== "clerk")), then pass upstreamToInstall to runSkillsAdd (both the array
param and the join string) and skip the call entirely if upstreamToInstall is
empty; keep installClerkSkillCore, skillList and prompt behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@skills/clerk/references/auth.md`:
- Around line 16-35: The bundled auth docs in skills/clerk/references/auth.md
are inaccurate vs the implementation in packages/cli-core/src/lib/plapi.ts
(lines referenced): update the doc text to match actual behavior — state that
prefix mismatches cause an error (not just a warning) and that Platform API auth
resolves only from CLERK_PLATFORM_API_KEY or the stored OAuth token (no
interactive prompt fallback), and remove or rephrase any guidance implying an
interactive prompt or silent fallback; reference the plapi.ts behavior when
rewording so readers/agents follow the CLI's real resolution flow.

---

Outside diff comments:
In `@packages/cli-core/src/commands/init/skills.ts`:
- Around line 60-90: upstreamSkills includes "clerk" which causes runSkillsAdd
to reinstall the staged local skill; filter out "clerk" after computing
upstreamSkills and before calling runSkillsAdd (e.g. const upstreamToInstall =
upstreamSkills.filter(s => s !== "clerk")), then pass upstreamToInstall to
runSkillsAdd (both the array param and the join string) and skip the call
entirely if upstreamToInstall is empty; keep installClerkSkillCore, skillList
and prompt behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d23c701e-a138-48bf-816c-9339054cbbb8

📥 Commits

Reviewing files that changed from the base of the PR and between 3b840b8 and 9c7d911.

📒 Files selected for processing (22)
  • .changeset/clerk-skill.md
  • README.md
  • packages/cli-core/src/cli-program.ts
  • packages/cli-core/src/commands/init/README.md
  • packages/cli-core/src/commands/init/bootstrap-registry.ts
  • packages/cli-core/src/commands/init/bootstrap.ts
  • packages/cli-core/src/commands/init/context.ts
  • packages/cli-core/src/commands/init/frameworks/types.ts
  • packages/cli-core/src/commands/init/index.ts
  • packages/cli-core/src/commands/init/skills.test.ts
  • packages/cli-core/src/commands/init/skills.ts
  • packages/cli-core/src/commands/skill/README.md
  • packages/cli-core/src/commands/skill/install.test.ts
  • packages/cli-core/src/commands/skill/install.ts
  • packages/cli-core/src/lib/package-manager.ts
  • packages/cli-core/src/lib/version.ts
  • scripts/build.ts
  • scripts/tsconfig.json
  • skills/clerk/SKILL.md
  • skills/clerk/references/agent-mode.md
  • skills/clerk/references/auth.md
  • skills/clerk/references/recipes.md
💤 Files with no reviewable changes (1)
  • packages/cli-core/src/commands/init/skills.test.ts

Comment on lines +16 to +35
### Backend API secret key resolution order

When you run `clerk api /users` (no `--platform`), the CLI picks the `sk_` key in this order:

1. `--secret-key <key>` flag (explicit override)
2. `CLERK_SECRET_KEY` environment variable
3. Auto-resolved from `--app <id>` (uses `CLERK_PLATFORM_API_KEY` or stored OAuth token to fetch the app's secret key)
4. Auto-resolved from the linked project profile (same mechanism as #3, but the app ID comes from the repo's link)

The CLI validates prefixes: passing `sk_test_...` to a production target or `ak_...` where `sk_...` is expected emits a warning.

### Platform API auth resolution order

When you run `clerk api --platform ...`, or any command that already uses PLAPI (`apps list`, `config pull`, `link`, etc.), the CLI picks the bearer token in this order:

1. `CLERK_PLATFORM_API_KEY` environment variable
2. Stored OAuth token from `clerk auth login`
3. Interactive prompt for a Platform API key (human mode only — fails in agent mode)

Set `CLERK_PLATFORM_API_KEY` for CI and scripted agent usage. Use `clerk auth login` for local interactive development.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Bundled auth guidance does not match the CLI's actual fallback/error behavior.

Line 25 says bad key types only warn, and Lines 31-33 say human mode can fall back to an interactive Platform API key prompt. The implementation in packages/cli-core/src/lib/plapi.ts:17-24,30-45 does neither: prefix mismatches throw, and PLAPI auth resolves from CLERK_PLATFORM_API_KEY or stored OAuth only, then errors. Since this file ships inside the bundled skill, agents following it will take paths the CLI cannot execute. Please align this reference with the real behavior before merge.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@skills/clerk/references/auth.md` around lines 16 - 35, The bundled auth docs
in skills/clerk/references/auth.md are inaccurate vs the implementation in
packages/cli-core/src/lib/plapi.ts (lines referenced): update the doc text to
match actual behavior — state that prefix mismatches cause an error (not just a
warning) and that Platform API auth resolves only from CLERK_PLATFORM_API_KEY or
the stored OAuth token (no interactive prompt fallback), and remove or rephrase
any guidance implying an interactive prompt or silent fallback; reference the
plapi.ts behavior when rewording so readers/agents follow the CLI's real
resolution flow.

@wyattjoh wyattjoh changed the title feat(init): bundle and pin the clerk skill to the CLI binary feat: Clerk CLI Skill Apr 15, 2026
wyattjoh added 13 commits April 15, 2026 18:02
Pulls the clerk-cli skill markdown files at <repo-root>/skills/clerk-cli/
into skills.ts as text imports (`import md from "./SKILL.md" with { type:
"text" }`), which resolve live during `bun run dev` and get embedded by
`bun build --compile`. The skill content therefore always matches the
binary running it, with no network lookup, no tag publishing race, and
no CLI_VERSION URL fallback.

At install time, `installSkills` stages the bundled content into a fresh
`mkdtemp` directory and invokes `<runner> skills add <tmpdir> --copy`.
The --copy flag is required: the `skills` CLI's default symlink mode
would point each agent's skill dir at the temp dir, which we delete
immediately after the install completes. Copy mode produces real files
in `.claude/skills/clerk-cli/` etc. and records the install in the
project's `skills-lock.json` with `sourceType: "local"` — which
correctly excludes it from `skills update` (the skill can only change
when the CLI itself is upgraded).

The upstream `clerk/skills` install continues to use the default symlink
mode against the remote source. The two installer calls share one
runner detection and fail independently.
Installs the bundled clerk-cli skill standalone so projects set up before
the skill was bundled, or CLIs upgraded since, can pull it in without
re-running init. `init` now delegates the clerk-cli portion to shared
core in commands/skill/install.ts, keeping a single runner detection
across clerk-cli and upstream framework skills.

Also extracts PACKAGE_MANAGERS as the canonical tuple plus derived type
in lib/package-manager.ts, reused by both `init --pm` and
`skill install --pm` choices. PM_PRIORITY in bootstrap keeps its
semantic name via `satisfies readonly PackageManager[]` plus a
compile-time exhaustiveness guard.

Fix the nano-staged oxlint hook to pass `-c .oxlintrc.json` explicitly
so override files (e.g. `unicorn/no-process-exit` off in cli-program.ts)
apply when linting specific paths; bare `oxlint <file>` does not
auto-discover the config.
Hoists the dev-version sentinel to a shared lib/version module so
cli-program.ts and install.ts stay in lockstep. Adds resolveCliVersion()
which maps both undefined and the 0.0.0-dev sentinel to undefined, letting
downstream callers treat unversioned binaries uniformly.

Threads the resolved version through withStagedClerkCliSkill so every
bundled asset has {{CLI_VERSION}} substituted at install time. The install
caller uses resolveCliVersion() instead of an inline typeof guard.
Import DEV_CLI_VERSION from packages/cli-core/src/lib/version.ts in
scripts/build.ts so the build script's default version arg stays in
lockstep with the sentinel used by the skill installer. Also extend
scripts/tsconfig.json to include globals.d.ts so CLI_VERSION is in
scope when tsc follows the cross-package import.
Remove the PackageManager type re-export from bootstrap-registry and
update consumers (bootstrap.ts, context.ts, index.ts) to import the
type directly from lib/package-manager.ts.
Adds init, apps create, open, completion, and skill install to the
Core commands table; adds --destructive to config patch/put; clarifies
config put semantics. Strengthens the Prerequisites section to make
'clerk doctor --json' the mandatory session-start check, with a note
to rerun 'clerk skill install' after upgrading the CLI so the bundled
skill matches the new binary.

Adds agent-mode behavior rows for 'apps create' (requires explicit
--json) and 'clerk open' (emits a JSON descriptor instead of launching
a browser), plus matching entries in the structured-outputs table.

Calls out 'clerk <command> --help' as the source of truth for flags so
the skill stays a hint rather than a spec, reducing drift surface.

Hidden commands (deploy, switch-env) remain undocumented.
Rename the bundled skill from `clerk-cli` to `clerk` everywhere the name
appears as a skill identifier: directory path, frontmatter `name:`, user-
facing copy, and the JS/TS identifiers that track it (import bindings,
`BUNDLED_CLERK_SKILL`, `withStagedClerkSkill`, `installClerkSkillCore`).

Leaves CLI-level identifiers untouched since changing them would orphan
user state on upgrade: `KEYCHAIN_SERVICE = "clerk-cli"` (macOS keychain),
`envPaths("clerk-cli", ...)` (OS config/cache paths), and the
`clerk-cli-mock-auth` test-fixture package name.
@wyattjoh wyattjoh force-pushed the feat/clerk-cli-skill-pinned branch from 9c7d911 to 61a2b63 Compare April 16, 2026 00:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant