Skip to content
Merged
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
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Daemon (src/daemon/daemon.ts) ── auto-spawned by IpcClient.ensureDaemonStar
- `${CLAUDE_PLUGIN_ROOT}` is expanded only in `hooks/hooks.json`, never in `statusLine.command`, and fails silently. That is why `open` writes resolved paths.
- Function hooks / mods (`plugin/hooks/register.tsx`, `plugin/mods/`) need `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1` (set in `sanitizeEnv`, `src/open/runtime.ts`) and claude >= 2.1.269. See `docs/mods.md`.
- Many tests pin prompt and manifest text (`prompt-layers`, `orchestrator-prose`, `plugin-manifest`, `tlc-spec-driven`, `roles`). Changing prose usually means updating those tests.
- The `commit` and `pr-writer` sections of the general agent are rendered from `skills/commit` and `skills/pr-writer` by `SKILL_PARTIALS` in `scripts/copy-plugin.mjs`, which swaps references to skills the prompt cannot load. Edit the skill; the build fails if an adaptation stops matching.
- Top-level `skills/` holds standalone skills. `skills/use-codedeck` also has an installed copy under `~/.claude`; edit both or the `/use-codedeck` command does not change.

## Testing notes
Expand Down
39 changes: 33 additions & 6 deletions plugin/agents/general.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ description: Do CodeDeck work directly in the current workspace, with evidence.

- Once the task is clear in a `codedeck run` worker, rename your session with `codedeck rename "$CODEDECK_SESSION_ID" <short-task-slug>`.

<!-- Source: ~/.claude/skills/commit/SKILL.md (vendored full text). Adaptations: (1) the create-branch skill reference is a one-line main/master rule below, the skill itself is not vendored; (2) any sentry-skills:commit reference points to the Commits section in this prompt; (3) Co-Authored-By names the harness that did the work, not Claude. -->
<!-- Generated from skills/commit/SKILL.md by scripts/copy-plugin.mjs. Edit the skill, not the agent file. -->

## Commits

Expand Down Expand Up @@ -172,7 +172,7 @@ Reason: Caused performance regression in production.

- [Sentry Commit Messages](https://develop.sentry.dev/engineering-practices/commit-messages/)

<!-- Source: ~/.claude/skills/pr-writer/SKILL.md (vendored full text). Adaptations: (1) the create-branch skill reference is a one-line main/master rule, the skill itself is not vendored; (2) the sentry-skills:commit reference below points to the Commits section in this prompt; (3) Co-Authored-By names the harness that did the work, not Claude. -->
<!-- Generated from skills/pr-writer/SKILL.md by scripts/copy-plugin.mjs. Edit the skill, not the agent file. -->

## Pull requests

Expand Down Expand Up @@ -251,6 +251,7 @@ Use this structure for PR descriptions (ignoring any repository PR templates):
- Links to relevant issues or tickets
- Context that isn't obvious from the code
- Notes on specific areas that need careful review
- Visual evidence when it passes the gate in Visual Evidence below

### Step 4: Create the PR

Expand Down Expand Up @@ -321,6 +322,36 @@ Reference issues in the PR body:
| `Refs GH-1234` | Links without closing |
| `Refs LINEAR-ABC-123` | Links Linear issue |

## Visual Evidence

Default to none. Add a visual only when a reviewer would otherwise have to check out the branch to see the change, or when the text needs a paragraph to describe what one picture shows. One visual per PR is the norm; never add one to fill space.

| Change | Evidence |
|--------|----------|
| UI layout or styling | Screenshot, before/after when it changes existing UI |
| Interaction or animation | GIF, 15s or less |
| CLI/TUI output | Fenced text block with the real output, not a screenshot |
| New flow across 3+ components, or a changed state machine | Mermaid diagram |
| Refactor, config, deps, internal bug fix, tests | None |

Rules:
- Capture from the running app (Playwright for web, `ffmpeg` to turn a recording into a GIF). Never mock, edit or stage a screenshot.
- A Mermaid diagram shows the mechanism the PR adds or changes, not the whole system. GitHub renders ` ```mermaid ` blocks natively.
- Put each visual under the sentence it supports, with a one-line caption.

Hosting images: `gh` cannot upload attachments, so push them to an orphan `pr-assets` branch and link them. Never commit them to the PR branch.

```bash
B=$(git branch --show-current)
git fetch -q origin pr-assets:pr-assets 2>/dev/null || git branch pr-assets "$(git commit-tree "$(git mktree </dev/null)" -m 'chore: Start PR assets')"
d=$(mktemp -d); git worktree add -q "$d" pr-assets
mkdir -p "$d/$B"; cp shot.png "$d/$B/"
git -C "$d" add -A && git -C "$d" commit -qm "chore: Add PR assets for $B" && git -C "$d" push -q origin pr-assets
git worktree remove "$d"
```

Link as `![caption](https://github.com/OWNER/REPO/blob/pr-assets/BRANCH/shot.png?raw=true)`. This form also renders on private repos. For a video that must stay a video, leave the file path in your report and say the user has to drag it into the PR on GitHub.

## Guidelines

- **One PR per feature/fix** - Don't bundle unrelated changes
Expand All @@ -338,14 +369,10 @@ gh api -X PATCH repos/{owner}/{repo}/pulls/PR_NUMBER -f body="$(cat <<'EOF'
Updated description here
EOF
)"
```

```bash
# Update PR title
gh api -X PATCH repos/{owner}/{repo}/pulls/PR_NUMBER -f title='new: Title here'
```

```bash
# Update both
gh api -X PATCH repos/{owner}/{repo}/pulls/PR_NUMBER \
-f title='new: Title' \
Expand Down
51 changes: 51 additions & 0 deletions scripts/copy-plugin.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,58 @@ function parseManifest(source, manifestPath) {
return { name, description, tools, includes, body };
}

// Partials generated from a standalone skill in skills/, so the skill stays
// the only copy. Each adaptation must match at least once, or the build fails
// instead of shipping a prompt that still points at a skill it cannot load.
const SKILLS = join(root, "skills");
const SKILL_PARTIALS = {
commit: {
heading: "## Commits",
adaptations: [
[
/Before committing, always check the current branch:[\s\S]*?If still on `main` or `master` \(e\.g\., the user aborted branch creation\), stop — do not commit\./,
"If `git branch --show-current` shows `main` or `master`, create a feature branch first unless the human explicitly asked to commit there.",
],
[
"When changes were primarily generated by a coding agent (like Claude Code), include the Co-Authored-By attribution in the commit footer:",
"When changes were primarily generated by a coding agent, include the Co-Authored-By attribution naming the harness that did the work in the commit footer:",
],
[/Co-Authored-By: Claude <noreply@anthropic\.com>/g, "Co-Authored-By: <harness that did the work>"],
],
},
"pr-writer": {
heading: "## Pull requests",
adaptations: [
[
"run the `sentry-skills:commit` skill first to commit them properly.",
"commit them first following the Commits section in this prompt.",
],
[
"invoke the `sentry-skills:commit` skill before proceeding.",
"commit them first following the Commits section in this prompt before proceeding.",
],
],
},
};

function renderSkillPartial(manifestPath, entry) {
const { heading, adaptations } = SKILL_PARTIALS[entry];
const file = join(SKILLS, entry, "SKILL.md");
let body = splitFrontmatter(readFileSync(file, "utf8"), file).body;
for (const [from, to] of adaptations) {
const hits = typeof from === "string" ? body.split(from).length - 1 : (body.match(from) ?? []).length;
if (hits === 0) throw new Error(`${manifestPath}: adaptation for skills/${entry} no longer matches: ${from}`);
body = body.replace(from, to);
}
if (body.includes("sentry-skills:") || body.includes("`create-branch` skill")) {
throw new Error(`${manifestPath}: skills/${entry} still references a skill the prompt cannot load`);
}
const header = `<!-- Generated from skills/${entry}/SKILL.md by scripts/copy-plugin.mjs. Edit the skill, not the agent file. -->`;
return `${header}\n\n${heading}\n\n${body}`;
}

function readPartial(manifestPath, entry) {
if (Object.hasOwn(SKILL_PARTIALS, entry)) return renderSkillPartial(manifestPath, entry);
const file = join(PARTIALS, `${entry}.md`);
if (!existsSync(file)) {
throw new Error(`${manifestPath} includes unknown partial "${entry}" (no ${file})`);
Expand Down
29 changes: 22 additions & 7 deletions plugin/prompts/_partials/commit.md → skills/commit/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
<!-- Source: ~/.claude/skills/commit/SKILL.md (vendored full text). Adaptations: (1) the create-branch skill reference is a one-line main/master rule below, the skill itself is not vendored; (2) any sentry-skills:commit reference points to the Commits section in this prompt; (3) Co-Authored-By names the harness that did the work, not Claude. -->

## Commits
---
name: commit
description: ALWAYS use this skill when committing code changes — never commit directly without it. Creates commits following Sentry conventions with proper conventional commit format and issue references. Trigger on any commit, git commit, save changes, or commit message task.
---

# Sentry Commit Messages

Follow these conventions when creating commits for Sentry projects.

## Prerequisites

If `git branch --show-current` shows `main` or `master`, create a feature branch first unless the human explicitly asked to commit there.
Before committing, always check the current branch:

```bash
git branch --show-current
```

**If you're on `main` or `master`, you MUST create a feature branch first** — unless the user explicitly asked to commit to main. Do not ask the user whether to create a branch; just proceed with branch creation. The `create-branch` skill will still propose a branch name for the user to confirm.

Use the `create-branch` skill to create the branch. After `create-branch` completes, verify the current branch has changed before proceeding:

```bash
git branch --show-current
```

If still on `main` or `master` (e.g., the user aborted branch creation), stop — do not commit.

## Format

Expand Down Expand Up @@ -69,10 +84,10 @@ Refs LINEAR-ABC-123

## AI-Generated Changes

When changes were primarily generated by a coding agent, include the Co-Authored-By attribution naming the harness that did the work in the commit footer:
When changes were primarily generated by a coding agent (like Claude Code), include the Co-Authored-By attribution in the commit footer:

```
Co-Authored-By: <harness that did the work>
Co-Authored-By: Claude <noreply@anthropic.com>
```

This is the only indicator of AI involvement that should appear in commits. Do not add phrases like "Generated by AI", "Written with Claude", or similar markers in the subject, body, or anywhere else in the commit message.
Expand All @@ -88,7 +103,7 @@ The user API could return null for deleted accounts, causing a crash
in the dashboard. Add null check before accessing user properties.

Fixes SENTRY-5678
Co-Authored-By: <harness that did the work>
Co-Authored-By: Claude <noreply@anthropic.com>
```

### Feature with scope
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<!-- Source: ~/.claude/skills/pr-writer/SKILL.md (vendored full text). Adaptations: (1) the create-branch skill reference is a one-line main/master rule, the skill itself is not vendored; (2) the sentry-skills:commit reference below points to the Commits section in this prompt; (3) Co-Authored-By names the harness that did the work, not Claude. -->

## Pull requests
---
name: pr-writer
description: ALWAYS use this skill when creating or updating pull requests — never create or edit a PR directly without it. Follows Sentry conventions for PR titles, descriptions, and issue references. Trigger on any create PR, open PR, submit PR, make PR,...
---

# PR Writer

Expand All @@ -10,14 +11,14 @@ Create pull requests following Sentry's engineering practices.

## Prerequisites

Before creating a PR, ensure all changes are committed. If there are uncommitted changes, commit them first following the Commits section in this prompt.
Before creating a PR, ensure all changes are committed. If there are uncommitted changes, run the `sentry-skills:commit` skill first to commit them properly.

```bash
# Check for uncommitted changes
git status --porcelain
```

If the output shows any uncommitted changes (modified, added, or untracked files that should be included), commit them first following the Commits section in this prompt before proceeding.
If the output shows any uncommitted changes (modified, added, or untracked files that should be included), invoke the `sentry-skills:commit` skill before proceeding.

## Process

Expand Down Expand Up @@ -77,6 +78,7 @@ Use this structure for PR descriptions (ignoring any repository PR templates):
- Links to relevant issues or tickets
- Context that isn't obvious from the code
- Notes on specific areas that need careful review
- Visual evidence when it passes the gate in Visual Evidence below

### Step 4: Create the PR

Expand Down Expand Up @@ -147,6 +149,36 @@ Reference issues in the PR body:
| `Refs GH-1234` | Links without closing |
| `Refs LINEAR-ABC-123` | Links Linear issue |

## Visual Evidence

Default to none. Add a visual only when a reviewer would otherwise have to check out the branch to see the change, or when the text needs a paragraph to describe what one picture shows. One visual per PR is the norm; never add one to fill space.

| Change | Evidence |
|--------|----------|
| UI layout or styling | Screenshot, before/after when it changes existing UI |
| Interaction or animation | GIF, 15s or less |
| CLI/TUI output | Fenced text block with the real output, not a screenshot |
| New flow across 3+ components, or a changed state machine | Mermaid diagram |
| Refactor, config, deps, internal bug fix, tests | None |

Rules:
- Capture from the running app (Playwright for web, `ffmpeg` to turn a recording into a GIF). Never mock, edit or stage a screenshot.
- A Mermaid diagram shows the mechanism the PR adds or changes, not the whole system. GitHub renders ` ```mermaid ` blocks natively.
- Put each visual under the sentence it supports, with a one-line caption.

Hosting images: `gh` cannot upload attachments, so push them to an orphan `pr-assets` branch and link them. Never commit them to the PR branch.

```bash
B=$(git branch --show-current)
git fetch -q origin pr-assets:pr-assets 2>/dev/null || git branch pr-assets "$(git commit-tree "$(git mktree </dev/null)" -m 'chore: Start PR assets')"
d=$(mktemp -d); git worktree add -q "$d" pr-assets
mkdir -p "$d/$B"; cp shot.png "$d/$B/"
git -C "$d" add -A && git -C "$d" commit -qm "chore: Add PR assets for $B" && git -C "$d" push -q origin pr-assets
git worktree remove "$d"
```

Link as `![caption](https://github.com/OWNER/REPO/blob/pr-assets/BRANCH/shot.png?raw=true)`. This form also renders on private repos. For a video that must stay a video, leave the file path in your report and say the user has to drag it into the PR on GitHub.

## Guidelines

- **One PR per feature/fix** - Don't bundle unrelated changes
Expand All @@ -164,14 +196,10 @@ gh api -X PATCH repos/{owner}/{repo}/pulls/PR_NUMBER -f body="$(cat <<'EOF'
Updated description here
EOF
)"
```

```bash
# Update PR title
gh api -X PATCH repos/{owner}/{repo}/pulls/PR_NUMBER -f title='new: Title here'
```

```bash
# Update both
gh api -X PATCH repos/{owner}/{repo}/pulls/PR_NUMBER \
-f title='new: Title' \
Expand Down
7 changes: 6 additions & 1 deletion tests/prompt-layers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { resolveRoleContract } from "../src/open/contract.js";
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const agentsDir = path.join(root, "plugin", "agents");
const partialsDir = path.join(root, "plugin", "prompts", "_partials");
// Rendered from skills/<name>/SKILL.md by copy-plugin.mjs, not stored in _partials.
const SKILL_PARTIALS = ["commit", "pr-writer"];
const manifestsDir = path.join(root, "plugin", "prompts", "roles");
const ultraFile = path.join(root, "plugin", "ultra.md");

Expand Down Expand Up @@ -98,7 +100,10 @@ describe("prompt layers: manifest validity", () => {

expect(includes.length).toBeGreaterThan(0);
for (const entry of includes) {
expect(fs.existsSync(path.join(partialsDir, `${entry}.md`),), `${role} includes ${entry}`).toBe(true);
const source = SKILL_PARTIALS.includes(entry)
? path.join(root, "skills", entry, "SKILL.md")
: path.join(partialsDir, `${entry}.md`);
expect(fs.existsSync(source), `${role} includes ${entry}`).toBe(true);
}
});

Expand Down
Loading