[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-sentry-junior-qa":3,"mdc--uoce6b-key":37,"related-org-sentry-junior-qa":1147,"related-repo-sentry-junior-qa":1321},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":12,"stars":26,"repoUrl":27,"updatedAt":28,"license":29,"forks":30,"topics":31,"repo":33,"sourceUrl":35,"mdContent":36},"junior-qa","validate Junior application changes","Validate Junior changes through local app-facing paths. Use for local client or agent QA, dashboard mock reporting UI QA, PR readiness, plugin CLI commands, skill\u002Ftool\u002Fprompt\u002Fplugin behavior, and behavior that tests do not cover well but can be exercised with `pnpm cli -- chat ...`, another `pnpm cli` command, or `JUNIOR_DASHBOARD_MOCK_CONVERSATIONS=true pnpm dev`.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},"sentry","Sentry","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fsentry.png","getsentry",[13,17,20,23],{"name":14,"slug":15,"type":16},"QA","qa","tag",{"name":18,"slug":19,"type":16},"Engineering","engineering",{"name":21,"slug":22,"type":16},"Testing","testing",{"name":24,"slug":25,"type":16},"Debugging","debugging",300,"https:\u002F\u002Fgithub.com\u002Fgetsentry\u002Fjunior","2026-07-31T06:23:35.910415",null,29,[32],"tag-non-production",{"repoUrl":27,"stars":26,"forks":30,"topics":34,"description":29},[32],"https:\u002F\u002Fgithub.com\u002Fgetsentry\u002Fjunior\u002Ftree\u002FHEAD\u002Fskills\u002Fjunior-qa","---\nname: junior-qa\ndescription: Validate Junior changes through local app-facing paths. Use for local client or agent QA, dashboard mock reporting UI QA, PR readiness, plugin CLI commands, skill\u002Ftool\u002Fprompt\u002Fplugin behavior, and behavior that tests do not cover well but can be exercised with `pnpm cli -- chat ...`, another `pnpm cli` command, or `JUNIOR_DASHBOARD_MOCK_CONVERSATIONS=true pnpm dev`.\n---\n\nUse the local Junior CLI to exercise behavior the test suite does not prove well.\nThe goal is to run the same app-facing path a developer or operator would use\nfrom `apps\u002Fexample`, inspect the result, and report concrete evidence.\n\nStart by reading `packages\u002Fjunior\u002Fsrc\u002Fchat\u002Flocal\u002FREADME.md`. Read the owning\npackage or module README when the changed behavior belongs elsewhere.\n\n## Running the Local CLI\n\nUse the repo wrapper so commands run from `apps\u002Fexample` with root and app env\nloaded. Pick the command and prompt that exercise the changed behavior; do not\ntreat any example prompt here as the required QA:\n\n```sh\npnpm cli -- chat -p \"\u003Ctargeted prompt>\"\n```\n\nFor agent behavior, prompts, skills, tools, and model-facing plugin behavior,\nuse `chat -p` or interactive `chat` with a prompt that naturally exercises the\nchange. A trivial exact-output prompt is only useful when the requested check is\nlimited to proving the local runner starts and delivers one response.\n\nFor host or plugin CLI behavior, call the command directly through the same\nwrapper:\n\n```sh\npnpm cli -- memory search --scope personal --scope-key local:local-cli --limit 5\n```\n\nUse example app discovery probes when the change touches skill or plugin\ndiscovery:\n\n```sh\npnpm cli -- chat -p \"\u002Fexample-local confirm local QA discovery\"\npnpm cli -- chat -p \"\u002Fexample-bundle-help\"\n```\n\nHealthy startup usually logs `SOUL.md`, `WORLD.md`, loaded plugins, and\ndiscovered skills. Treat those logs as useful evidence that the example app path\nwas exercised.\n\n## Dashboard UI QA\n\nFor dashboard UI changes that depend on reporting payload shape, use the typed\nmock reporting overlay before relying on ad-hoc local conversations:\n\n```sh\nJUNIOR_DASHBOARD_MOCK_CONVERSATIONS=true pnpm dev\n```\n\nThen open the dashboard in a browser and exercise the relevant conversation,\ntranscript, search, or conversation stats surface. The mock overlay returns\nread-only `@sentry\u002Fjunior\u002Freporting` conversation API-shaped data, including\ndashboard QA edge cases such as activity-only tool rows and inverted tool\ntimestamps. It also includes an advisor tool call\u002Fresult paired with advisor\nsubagent activity so transcript rendering can be checked against nested tool\nactivity without manufacturing a live agent run. Use it when a UI change needs\ndeterministic reporting records that are hard to produce through a live local\nchat. Plugin report data is pass-through from the configured reporting provider\nand needs separate validation.\n\nThe root dev command owns local auth-disabled defaults and the production-like\nNitro preset. If it fails to start, diagnose or report the dev runner failure;\ndo not change `apps\u002Fexample\u002Fnitro.config.ts`, dashboard auth settings, or OAuth\nconfiguration to make visual QA run.\n\nDo not treat mock dashboard data as proof of runtime ingestion, Slack delivery,\ncredential behavior, or model behavior. Pair it with local CLI or integration\ntests when the changed contract crosses those boundaries.\n\n## Choosing a Probe\n\nPick the smallest local CLI run that demonstrates the changed behavior:\n\n- Prefer a targeted prompt or direct CLI command tied to the modified feature.\n- Use exact-output prompts for simple agent routing or prompt-context checks.\n- Use natural-language prompts when the behavior is an agent\u002Ftool workflow.\n- Use direct plugin commands when the behavior is an operator CLI surface.\n- Use interactive `pnpm cli -- chat` when continuity across turns matters.\n- Use dashboard mock reporting when the behavior is dashboard rendering,\n  filtering, search, or metrics over reporting API payloads.\n- Do not use local CLI to claim Slack-only behavior, such as Slack formatting,\n  delivery retries, reactions, files, or OAuth UI.\n\nAutomated tests, typechecks, linters, and evals are separate validation. They do\nnot replace local QA evidence from running the client or agent.\n\n## OAuth Flow QA (MCP and Plugin)\n\nJunior has two OAuth pause\u002Fresume flows:\n\n- Plugin (non-MCP) OAuth: sandbox egress `auth_required` signal resumes via\n  `\u002Fapi\u002Foauth\u002Fcallback\u002F\u003Cprovider>`. In `apps\u002Fexample` the `sentry` plugin is\n  the OAuth-manifest provider (`SENTRY_CLIENT_ID`\u002F`SENTRY_CLIENT_SECRET`).\n- MCP OAuth: a remote MCP server 401 challenge resumes via\n  `\u002Fapi\u002Foauth\u002Fcallback\u002Fmcp\u002F\u003Cprovider>`. In `apps\u002Fexample` the `linear`,\n  `notion`, and `hex` plugins use remote MCP URLs.\n\nThe local CLI prints the private authorization URL, waits for the provider\ncallback, and resumes the same turn as the `local-cli` user. Keep `pnpm dev`\nrunning so the configured public callback and tunnel can verify the signed\nlocal state and redirect the browser to the CLI's loopback listener.\n\nBefore starting the chat command:\n\n1. Keep one `pnpm dev` process running in the foreground.\n2. Confirm only one Cloudflare tunnel for this development hostname is active.\n3. Probe both callback hops. Each request should reach Junior and return `400`\n   because the probe intentionally omits OAuth state:\n\n```sh\ncurl -sS -o \u002Fdev\u002Fnull -w '%{http_code}\\n' \\\n  http:\u002F\u002F127.0.0.1:3000\u002Fapi\u002Foauth\u002Fcallback\u002Fmcp\u002Flinear\ncurl -sS -o \u002Fdev\u002Fnull -w '%{http_code}\\n' \\\n  https:\u002F\u002Fjunior-dev.sentry.cool\u002Fapi\u002Foauth\u002Fcallback\u002Fmcp\u002Flinear\n```\n\nDo not present an authorization URL until both probes return `400`. A public\n`502` means the tunnel is running without a reachable local server; restart the\ndev command and re-run both probes before creating a fresh OAuth attempt.\n\n```sh\npnpm cli -- chat -p \"Use the linear skill to list Linear teams.\"\n```\n\nExpect an authorization URL on stderr. Complete the provider flow in a browser;\nthe same CLI process should then continue the blocked request and print its\nreply without requiring the prompt again.\n\nUse the integration tests as the deterministic check for both local and Slack\nresume behavior:\n\n```sh\npnpm --filter @sentry\u002Fjunior exec vitest run tests\u002Fintegration\u002Flocal-agent-runner.test.ts\npnpm --filter @sentry\u002Fjunior exec vitest run tests\u002Fintegration\u002Foauth-callback.test.ts\npnpm --filter @sentry\u002Fjunior exec vitest run tests\u002Fintegration\u002Fmcp-oauth-callback.test.ts tests\u002Fintegration\u002Fmcp-auth-runtime-slack.test.ts\n```\n\nFor SQL conversation storage changes, verify the resumed turn rebuilds context\nfrom SQL, not `thread-state` mirrors: conversation context must hydrate from\n`junior_conversation_messages` (`hydrateConversationMessages`) and pi history\nfrom `junior_conversation_events` through the Pi adapter (`loadProjection`). In\nthose tests, transcripts seeded only into `thread-state` must also be persisted\nto SQL (`persistConversationMessages`) before the callback runs, and the\nresumed agent-run input `conversationContext` must contain the SQL-seeded\nmessages.\n\n## Failure Handling\n\nIf local chat fails because credentials are missing or expired, refresh the\nenvironment when appropriate with `pnpm dev:env`, then rerun the same command.\nIf local chat fails with a `junior_conversation_messages` or\n`junior_conversation_events` query error, the local Postgres schema predates the\nSQL conversation storage cutover; run `pnpm cli -- upgrade`, then rerun.\nIf Redis errors appear during ordinary local QA, check whether\n`JUNIOR_STATE_ADAPTER=redis` was set; local chat normally defaults to memory\nstate.\nIf OAuth returns `502`, verify port 3000 is listening and remove stale duplicate\ndev servers or tunnel clients before retrying. If the provider says the\nauthorization expired, discard that URL and start a fresh chat attempt after\nthe callback health checks pass.\n\nIf the model answer is too loose to prove the behavior, use a narrower prompt,\nan exact-output prompt, interactive mode, or a direct plugin CLI command. If the\nbehavior cannot be exercised through the local client\u002Fagent, say local QA is\ninsufficient and name the runtime surface that still needs manual coverage.\n\n## Reporting\n\nReport:\n\n- the exact `pnpm cli -- ...` commands run\n- for dashboard mock QA, the dev-server command, URL, mock conversation or page\n  inspected, and the visible UI evidence\n- exit status and the key output that proves the behavior\n- whether `apps\u002Fexample` loaded the expected app\u002Fplugin\u002Fskill path\n- whether local QA was sufficient, or what remains unproven locally\n\nKeep any automated test\u002Flint\u002Ftypecheck\u002Feval results in a separate validation\nsection so they are not confused with local QA.\n",{"data":38,"body":39},{"name":4,"description":6},{"type":40,"children":41},"root",[42,59,72,79,91,151,172,177,240,245,325,346,352,357,393,406,419,424,430,435,483,488,494,499,595,616,621,655,767,787,830,835,840,953,1021,1027,1077,1082,1088,1093,1136,1141],{"type":43,"tag":44,"props":45,"children":46},"element","p",{},[47,50,57],{"type":48,"value":49},"text","Use the local Junior CLI to exercise behavior the test suite does not prove well.\nThe goal is to run the same app-facing path a developer or operator would use\nfrom ",{"type":43,"tag":51,"props":52,"children":54},"code",{"className":53},[],[55],{"type":48,"value":56},"apps\u002Fexample",{"type":48,"value":58},", inspect the result, and report concrete evidence.",{"type":43,"tag":44,"props":60,"children":61},{},[62,64,70],{"type":48,"value":63},"Start by reading ",{"type":43,"tag":51,"props":65,"children":67},{"className":66},[],[68],{"type":48,"value":69},"packages\u002Fjunior\u002Fsrc\u002Fchat\u002Flocal\u002FREADME.md",{"type":48,"value":71},". Read the owning\npackage or module README when the changed behavior belongs elsewhere.",{"type":43,"tag":73,"props":74,"children":76},"h2",{"id":75},"running-the-local-cli",[77],{"type":48,"value":78},"Running the Local CLI",{"type":43,"tag":44,"props":80,"children":81},{},[82,84,89],{"type":48,"value":83},"Use the repo wrapper so commands run from ",{"type":43,"tag":51,"props":85,"children":87},{"className":86},[],[88],{"type":48,"value":56},{"type":48,"value":90}," with root and app env\nloaded. Pick the command and prompt that exercise the changed behavior; do not\ntreat any example prompt here as the required QA:",{"type":43,"tag":92,"props":93,"children":98},"pre",{"className":94,"code":95,"language":96,"meta":97,"style":97},"language-sh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm cli -- chat -p \"\u003Ctargeted prompt>\"\n","sh","",[99],{"type":43,"tag":51,"props":100,"children":101},{"__ignoreMap":97},[102],{"type":43,"tag":103,"props":104,"children":107},"span",{"class":105,"line":106},"line",1,[108,114,120,125,130,135,141,146],{"type":43,"tag":103,"props":109,"children":111},{"style":110},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[112],{"type":48,"value":113},"pnpm",{"type":43,"tag":103,"props":115,"children":117},{"style":116},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[118],{"type":48,"value":119}," cli",{"type":43,"tag":103,"props":121,"children":122},{"style":116},[123],{"type":48,"value":124}," --",{"type":43,"tag":103,"props":126,"children":127},{"style":116},[128],{"type":48,"value":129}," chat",{"type":43,"tag":103,"props":131,"children":132},{"style":116},[133],{"type":48,"value":134}," -p",{"type":43,"tag":103,"props":136,"children":138},{"style":137},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[139],{"type":48,"value":140}," \"",{"type":43,"tag":103,"props":142,"children":143},{"style":116},[144],{"type":48,"value":145},"\u003Ctargeted prompt>",{"type":43,"tag":103,"props":147,"children":148},{"style":137},[149],{"type":48,"value":150},"\"\n",{"type":43,"tag":44,"props":152,"children":153},{},[154,156,162,164,170],{"type":48,"value":155},"For agent behavior, prompts, skills, tools, and model-facing plugin behavior,\nuse ",{"type":43,"tag":51,"props":157,"children":159},{"className":158},[],[160],{"type":48,"value":161},"chat -p",{"type":48,"value":163}," or interactive ",{"type":43,"tag":51,"props":165,"children":167},{"className":166},[],[168],{"type":48,"value":169},"chat",{"type":48,"value":171}," with a prompt that naturally exercises the\nchange. A trivial exact-output prompt is only useful when the requested check is\nlimited to proving the local runner starts and delivers one response.",{"type":43,"tag":44,"props":173,"children":174},{},[175],{"type":48,"value":176},"For host or plugin CLI behavior, call the command directly through the same\nwrapper:",{"type":43,"tag":92,"props":178,"children":180},{"className":94,"code":179,"language":96,"meta":97,"style":97},"pnpm cli -- memory search --scope personal --scope-key local:local-cli --limit 5\n",[181],{"type":43,"tag":51,"props":182,"children":183},{"__ignoreMap":97},[184],{"type":43,"tag":103,"props":185,"children":186},{"class":105,"line":106},[187,191,195,199,204,209,214,219,224,229,234],{"type":43,"tag":103,"props":188,"children":189},{"style":110},[190],{"type":48,"value":113},{"type":43,"tag":103,"props":192,"children":193},{"style":116},[194],{"type":48,"value":119},{"type":43,"tag":103,"props":196,"children":197},{"style":116},[198],{"type":48,"value":124},{"type":43,"tag":103,"props":200,"children":201},{"style":116},[202],{"type":48,"value":203}," memory",{"type":43,"tag":103,"props":205,"children":206},{"style":116},[207],{"type":48,"value":208}," search",{"type":43,"tag":103,"props":210,"children":211},{"style":116},[212],{"type":48,"value":213}," --scope",{"type":43,"tag":103,"props":215,"children":216},{"style":116},[217],{"type":48,"value":218}," personal",{"type":43,"tag":103,"props":220,"children":221},{"style":116},[222],{"type":48,"value":223}," --scope-key",{"type":43,"tag":103,"props":225,"children":226},{"style":116},[227],{"type":48,"value":228}," local:local-cli",{"type":43,"tag":103,"props":230,"children":231},{"style":116},[232],{"type":48,"value":233}," --limit",{"type":43,"tag":103,"props":235,"children":237},{"style":236},"--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C",[238],{"type":48,"value":239}," 5\n",{"type":43,"tag":44,"props":241,"children":242},{},[243],{"type":48,"value":244},"Use example app discovery probes when the change touches skill or plugin\ndiscovery:",{"type":43,"tag":92,"props":246,"children":248},{"className":94,"code":247,"language":96,"meta":97,"style":97},"pnpm cli -- chat -p \"\u002Fexample-local confirm local QA discovery\"\npnpm cli -- chat -p \"\u002Fexample-bundle-help\"\n",[249],{"type":43,"tag":51,"props":250,"children":251},{"__ignoreMap":97},[252,288],{"type":43,"tag":103,"props":253,"children":254},{"class":105,"line":106},[255,259,263,267,271,275,279,284],{"type":43,"tag":103,"props":256,"children":257},{"style":110},[258],{"type":48,"value":113},{"type":43,"tag":103,"props":260,"children":261},{"style":116},[262],{"type":48,"value":119},{"type":43,"tag":103,"props":264,"children":265},{"style":116},[266],{"type":48,"value":124},{"type":43,"tag":103,"props":268,"children":269},{"style":116},[270],{"type":48,"value":129},{"type":43,"tag":103,"props":272,"children":273},{"style":116},[274],{"type":48,"value":134},{"type":43,"tag":103,"props":276,"children":277},{"style":137},[278],{"type":48,"value":140},{"type":43,"tag":103,"props":280,"children":281},{"style":116},[282],{"type":48,"value":283},"\u002Fexample-local confirm local QA discovery",{"type":43,"tag":103,"props":285,"children":286},{"style":137},[287],{"type":48,"value":150},{"type":43,"tag":103,"props":289,"children":291},{"class":105,"line":290},2,[292,296,300,304,308,312,316,321],{"type":43,"tag":103,"props":293,"children":294},{"style":110},[295],{"type":48,"value":113},{"type":43,"tag":103,"props":297,"children":298},{"style":116},[299],{"type":48,"value":119},{"type":43,"tag":103,"props":301,"children":302},{"style":116},[303],{"type":48,"value":124},{"type":43,"tag":103,"props":305,"children":306},{"style":116},[307],{"type":48,"value":129},{"type":43,"tag":103,"props":309,"children":310},{"style":116},[311],{"type":48,"value":134},{"type":43,"tag":103,"props":313,"children":314},{"style":137},[315],{"type":48,"value":140},{"type":43,"tag":103,"props":317,"children":318},{"style":116},[319],{"type":48,"value":320},"\u002Fexample-bundle-help",{"type":43,"tag":103,"props":322,"children":323},{"style":137},[324],{"type":48,"value":150},{"type":43,"tag":44,"props":326,"children":327},{},[328,330,336,338,344],{"type":48,"value":329},"Healthy startup usually logs ",{"type":43,"tag":51,"props":331,"children":333},{"className":332},[],[334],{"type":48,"value":335},"SOUL.md",{"type":48,"value":337},", ",{"type":43,"tag":51,"props":339,"children":341},{"className":340},[],[342],{"type":48,"value":343},"WORLD.md",{"type":48,"value":345},", loaded plugins, and\ndiscovered skills. Treat those logs as useful evidence that the example app path\nwas exercised.",{"type":43,"tag":73,"props":347,"children":349},{"id":348},"dashboard-ui-qa",[350],{"type":48,"value":351},"Dashboard UI QA",{"type":43,"tag":44,"props":353,"children":354},{},[355],{"type":48,"value":356},"For dashboard UI changes that depend on reporting payload shape, use the typed\nmock reporting overlay before relying on ad-hoc local conversations:",{"type":43,"tag":92,"props":358,"children":360},{"className":94,"code":359,"language":96,"meta":97,"style":97},"JUNIOR_DASHBOARD_MOCK_CONVERSATIONS=true pnpm dev\n",[361],{"type":43,"tag":51,"props":362,"children":363},{"__ignoreMap":97},[364],{"type":43,"tag":103,"props":365,"children":366},{"class":105,"line":106},[367,373,378,383,388],{"type":43,"tag":103,"props":368,"children":370},{"style":369},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[371],{"type":48,"value":372},"JUNIOR_DASHBOARD_MOCK_CONVERSATIONS",{"type":43,"tag":103,"props":374,"children":375},{"style":137},[376],{"type":48,"value":377},"=",{"type":43,"tag":103,"props":379,"children":380},{"style":116},[381],{"type":48,"value":382},"true",{"type":43,"tag":103,"props":384,"children":385},{"style":110},[386],{"type":48,"value":387}," pnpm",{"type":43,"tag":103,"props":389,"children":390},{"style":116},[391],{"type":48,"value":392}," dev\n",{"type":43,"tag":44,"props":394,"children":395},{},[396,398,404],{"type":48,"value":397},"Then open the dashboard in a browser and exercise the relevant conversation,\ntranscript, search, or conversation stats surface. The mock overlay returns\nread-only ",{"type":43,"tag":51,"props":399,"children":401},{"className":400},[],[402],{"type":48,"value":403},"@sentry\u002Fjunior\u002Freporting",{"type":48,"value":405}," conversation API-shaped data, including\ndashboard QA edge cases such as activity-only tool rows and inverted tool\ntimestamps. It also includes an advisor tool call\u002Fresult paired with advisor\nsubagent activity so transcript rendering can be checked against nested tool\nactivity without manufacturing a live agent run. Use it when a UI change needs\ndeterministic reporting records that are hard to produce through a live local\nchat. Plugin report data is pass-through from the configured reporting provider\nand needs separate validation.",{"type":43,"tag":44,"props":407,"children":408},{},[409,411,417],{"type":48,"value":410},"The root dev command owns local auth-disabled defaults and the production-like\nNitro preset. If it fails to start, diagnose or report the dev runner failure;\ndo not change ",{"type":43,"tag":51,"props":412,"children":414},{"className":413},[],[415],{"type":48,"value":416},"apps\u002Fexample\u002Fnitro.config.ts",{"type":48,"value":418},", dashboard auth settings, or OAuth\nconfiguration to make visual QA run.",{"type":43,"tag":44,"props":420,"children":421},{},[422],{"type":48,"value":423},"Do not treat mock dashboard data as proof of runtime ingestion, Slack delivery,\ncredential behavior, or model behavior. Pair it with local CLI or integration\ntests when the changed contract crosses those boundaries.",{"type":43,"tag":73,"props":425,"children":427},{"id":426},"choosing-a-probe",[428],{"type":48,"value":429},"Choosing a Probe",{"type":43,"tag":44,"props":431,"children":432},{},[433],{"type":48,"value":434},"Pick the smallest local CLI run that demonstrates the changed behavior:",{"type":43,"tag":436,"props":437,"children":438},"ul",{},[439,445,450,455,460,473,478],{"type":43,"tag":440,"props":441,"children":442},"li",{},[443],{"type":48,"value":444},"Prefer a targeted prompt or direct CLI command tied to the modified feature.",{"type":43,"tag":440,"props":446,"children":447},{},[448],{"type":48,"value":449},"Use exact-output prompts for simple agent routing or prompt-context checks.",{"type":43,"tag":440,"props":451,"children":452},{},[453],{"type":48,"value":454},"Use natural-language prompts when the behavior is an agent\u002Ftool workflow.",{"type":43,"tag":440,"props":456,"children":457},{},[458],{"type":48,"value":459},"Use direct plugin commands when the behavior is an operator CLI surface.",{"type":43,"tag":440,"props":461,"children":462},{},[463,465,471],{"type":48,"value":464},"Use interactive ",{"type":43,"tag":51,"props":466,"children":468},{"className":467},[],[469],{"type":48,"value":470},"pnpm cli -- chat",{"type":48,"value":472}," when continuity across turns matters.",{"type":43,"tag":440,"props":474,"children":475},{},[476],{"type":48,"value":477},"Use dashboard mock reporting when the behavior is dashboard rendering,\nfiltering, search, or metrics over reporting API payloads.",{"type":43,"tag":440,"props":479,"children":480},{},[481],{"type":48,"value":482},"Do not use local CLI to claim Slack-only behavior, such as Slack formatting,\ndelivery retries, reactions, files, or OAuth UI.",{"type":43,"tag":44,"props":484,"children":485},{},[486],{"type":48,"value":487},"Automated tests, typechecks, linters, and evals are separate validation. They do\nnot replace local QA evidence from running the client or agent.",{"type":43,"tag":73,"props":489,"children":491},{"id":490},"oauth-flow-qa-mcp-and-plugin",[492],{"type":48,"value":493},"OAuth Flow QA (MCP and Plugin)",{"type":43,"tag":44,"props":495,"children":496},{},[497],{"type":48,"value":498},"Junior has two OAuth pause\u002Fresume flows:",{"type":43,"tag":436,"props":500,"children":501},{},[502,553],{"type":43,"tag":440,"props":503,"children":504},{},[505,507,513,515,521,523,528,530,535,537,543,545,551],{"type":48,"value":506},"Plugin (non-MCP) OAuth: sandbox egress ",{"type":43,"tag":51,"props":508,"children":510},{"className":509},[],[511],{"type":48,"value":512},"auth_required",{"type":48,"value":514}," signal resumes via\n",{"type":43,"tag":51,"props":516,"children":518},{"className":517},[],[519],{"type":48,"value":520},"\u002Fapi\u002Foauth\u002Fcallback\u002F\u003Cprovider>",{"type":48,"value":522},". In ",{"type":43,"tag":51,"props":524,"children":526},{"className":525},[],[527],{"type":48,"value":56},{"type":48,"value":529}," the ",{"type":43,"tag":51,"props":531,"children":533},{"className":532},[],[534],{"type":48,"value":8},{"type":48,"value":536}," plugin is\nthe OAuth-manifest provider (",{"type":43,"tag":51,"props":538,"children":540},{"className":539},[],[541],{"type":48,"value":542},"SENTRY_CLIENT_ID",{"type":48,"value":544},"\u002F",{"type":43,"tag":51,"props":546,"children":548},{"className":547},[],[549],{"type":48,"value":550},"SENTRY_CLIENT_SECRET",{"type":48,"value":552},").",{"type":43,"tag":440,"props":554,"children":555},{},[556,558,564,565,570,571,577,579,585,587,593],{"type":48,"value":557},"MCP OAuth: a remote MCP server 401 challenge resumes via\n",{"type":43,"tag":51,"props":559,"children":561},{"className":560},[],[562],{"type":48,"value":563},"\u002Fapi\u002Foauth\u002Fcallback\u002Fmcp\u002F\u003Cprovider>",{"type":48,"value":522},{"type":43,"tag":51,"props":566,"children":568},{"className":567},[],[569],{"type":48,"value":56},{"type":48,"value":529},{"type":43,"tag":51,"props":572,"children":574},{"className":573},[],[575],{"type":48,"value":576},"linear",{"type":48,"value":578},",\n",{"type":43,"tag":51,"props":580,"children":582},{"className":581},[],[583],{"type":48,"value":584},"notion",{"type":48,"value":586},", and ",{"type":43,"tag":51,"props":588,"children":590},{"className":589},[],[591],{"type":48,"value":592},"hex",{"type":48,"value":594}," plugins use remote MCP URLs.",{"type":43,"tag":44,"props":596,"children":597},{},[598,600,606,608,614],{"type":48,"value":599},"The local CLI prints the private authorization URL, waits for the provider\ncallback, and resumes the same turn as the ",{"type":43,"tag":51,"props":601,"children":603},{"className":602},[],[604],{"type":48,"value":605},"local-cli",{"type":48,"value":607}," user. Keep ",{"type":43,"tag":51,"props":609,"children":611},{"className":610},[],[612],{"type":48,"value":613},"pnpm dev",{"type":48,"value":615},"\nrunning so the configured public callback and tunnel can verify the signed\nlocal state and redirect the browser to the CLI's loopback listener.",{"type":43,"tag":44,"props":617,"children":618},{},[619],{"type":48,"value":620},"Before starting the chat command:",{"type":43,"tag":622,"props":623,"children":624},"ol",{},[625,637,642],{"type":43,"tag":440,"props":626,"children":627},{},[628,630,635],{"type":48,"value":629},"Keep one ",{"type":43,"tag":51,"props":631,"children":633},{"className":632},[],[634],{"type":48,"value":613},{"type":48,"value":636}," process running in the foreground.",{"type":43,"tag":440,"props":638,"children":639},{},[640],{"type":48,"value":641},"Confirm only one Cloudflare tunnel for this development hostname is active.",{"type":43,"tag":440,"props":643,"children":644},{},[645,647,653],{"type":48,"value":646},"Probe both callback hops. Each request should reach Junior and return ",{"type":43,"tag":51,"props":648,"children":650},{"className":649},[],[651],{"type":48,"value":652},"400",{"type":48,"value":654},"\nbecause the probe intentionally omits OAuth state:",{"type":43,"tag":92,"props":656,"children":658},{"className":94,"code":657,"language":96,"meta":97,"style":97},"curl -sS -o \u002Fdev\u002Fnull -w '%{http_code}\\n' \\\n  http:\u002F\u002F127.0.0.1:3000\u002Fapi\u002Foauth\u002Fcallback\u002Fmcp\u002Flinear\ncurl -sS -o \u002Fdev\u002Fnull -w '%{http_code}\\n' \\\n  https:\u002F\u002Fjunior-dev.sentry.cool\u002Fapi\u002Foauth\u002Fcallback\u002Fmcp\u002Flinear\n",[659],{"type":43,"tag":51,"props":660,"children":661},{"__ignoreMap":97},[662,710,718,758],{"type":43,"tag":103,"props":663,"children":664},{"class":105,"line":106},[665,670,675,680,685,690,695,700,705],{"type":43,"tag":103,"props":666,"children":667},{"style":110},[668],{"type":48,"value":669},"curl",{"type":43,"tag":103,"props":671,"children":672},{"style":116},[673],{"type":48,"value":674}," -sS",{"type":43,"tag":103,"props":676,"children":677},{"style":116},[678],{"type":48,"value":679}," -o",{"type":43,"tag":103,"props":681,"children":682},{"style":116},[683],{"type":48,"value":684}," \u002Fdev\u002Fnull",{"type":43,"tag":103,"props":686,"children":687},{"style":116},[688],{"type":48,"value":689}," -w",{"type":43,"tag":103,"props":691,"children":692},{"style":137},[693],{"type":48,"value":694}," '",{"type":43,"tag":103,"props":696,"children":697},{"style":116},[698],{"type":48,"value":699},"%{http_code}\\n",{"type":43,"tag":103,"props":701,"children":702},{"style":137},[703],{"type":48,"value":704},"'",{"type":43,"tag":103,"props":706,"children":707},{"style":369},[708],{"type":48,"value":709}," \\\n",{"type":43,"tag":103,"props":711,"children":712},{"class":105,"line":290},[713],{"type":43,"tag":103,"props":714,"children":715},{"style":116},[716],{"type":48,"value":717},"  http:\u002F\u002F127.0.0.1:3000\u002Fapi\u002Foauth\u002Fcallback\u002Fmcp\u002Flinear\n",{"type":43,"tag":103,"props":719,"children":721},{"class":105,"line":720},3,[722,726,730,734,738,742,746,750,754],{"type":43,"tag":103,"props":723,"children":724},{"style":110},[725],{"type":48,"value":669},{"type":43,"tag":103,"props":727,"children":728},{"style":116},[729],{"type":48,"value":674},{"type":43,"tag":103,"props":731,"children":732},{"style":116},[733],{"type":48,"value":679},{"type":43,"tag":103,"props":735,"children":736},{"style":116},[737],{"type":48,"value":684},{"type":43,"tag":103,"props":739,"children":740},{"style":116},[741],{"type":48,"value":689},{"type":43,"tag":103,"props":743,"children":744},{"style":137},[745],{"type":48,"value":694},{"type":43,"tag":103,"props":747,"children":748},{"style":116},[749],{"type":48,"value":699},{"type":43,"tag":103,"props":751,"children":752},{"style":137},[753],{"type":48,"value":704},{"type":43,"tag":103,"props":755,"children":756},{"style":369},[757],{"type":48,"value":709},{"type":43,"tag":103,"props":759,"children":761},{"class":105,"line":760},4,[762],{"type":43,"tag":103,"props":763,"children":764},{"style":116},[765],{"type":48,"value":766},"  https:\u002F\u002Fjunior-dev.sentry.cool\u002Fapi\u002Foauth\u002Fcallback\u002Fmcp\u002Flinear\n",{"type":43,"tag":44,"props":768,"children":769},{},[770,772,777,779,785],{"type":48,"value":771},"Do not present an authorization URL until both probes return ",{"type":43,"tag":51,"props":773,"children":775},{"className":774},[],[776],{"type":48,"value":652},{"type":48,"value":778},". A public\n",{"type":43,"tag":51,"props":780,"children":782},{"className":781},[],[783],{"type":48,"value":784},"502",{"type":48,"value":786}," means the tunnel is running without a reachable local server; restart the\ndev command and re-run both probes before creating a fresh OAuth attempt.",{"type":43,"tag":92,"props":788,"children":790},{"className":94,"code":789,"language":96,"meta":97,"style":97},"pnpm cli -- chat -p \"Use the linear skill to list Linear teams.\"\n",[791],{"type":43,"tag":51,"props":792,"children":793},{"__ignoreMap":97},[794],{"type":43,"tag":103,"props":795,"children":796},{"class":105,"line":106},[797,801,805,809,813,817,821,826],{"type":43,"tag":103,"props":798,"children":799},{"style":110},[800],{"type":48,"value":113},{"type":43,"tag":103,"props":802,"children":803},{"style":116},[804],{"type":48,"value":119},{"type":43,"tag":103,"props":806,"children":807},{"style":116},[808],{"type":48,"value":124},{"type":43,"tag":103,"props":810,"children":811},{"style":116},[812],{"type":48,"value":129},{"type":43,"tag":103,"props":814,"children":815},{"style":116},[816],{"type":48,"value":134},{"type":43,"tag":103,"props":818,"children":819},{"style":137},[820],{"type":48,"value":140},{"type":43,"tag":103,"props":822,"children":823},{"style":116},[824],{"type":48,"value":825},"Use the linear skill to list Linear teams.",{"type":43,"tag":103,"props":827,"children":828},{"style":137},[829],{"type":48,"value":150},{"type":43,"tag":44,"props":831,"children":832},{},[833],{"type":48,"value":834},"Expect an authorization URL on stderr. Complete the provider flow in a browser;\nthe same CLI process should then continue the blocked request and print its\nreply without requiring the prompt again.",{"type":43,"tag":44,"props":836,"children":837},{},[838],{"type":48,"value":839},"Use the integration tests as the deterministic check for both local and Slack\nresume behavior:",{"type":43,"tag":92,"props":841,"children":843},{"className":94,"code":842,"language":96,"meta":97,"style":97},"pnpm --filter @sentry\u002Fjunior exec vitest run tests\u002Fintegration\u002Flocal-agent-runner.test.ts\npnpm --filter @sentry\u002Fjunior exec vitest run tests\u002Fintegration\u002Foauth-callback.test.ts\npnpm --filter @sentry\u002Fjunior exec vitest run tests\u002Fintegration\u002Fmcp-oauth-callback.test.ts tests\u002Fintegration\u002Fmcp-auth-runtime-slack.test.ts\n",[844],{"type":43,"tag":51,"props":845,"children":846},{"__ignoreMap":97},[847,884,916],{"type":43,"tag":103,"props":848,"children":849},{"class":105,"line":106},[850,854,859,864,869,874,879],{"type":43,"tag":103,"props":851,"children":852},{"style":110},[853],{"type":48,"value":113},{"type":43,"tag":103,"props":855,"children":856},{"style":116},[857],{"type":48,"value":858}," --filter",{"type":43,"tag":103,"props":860,"children":861},{"style":116},[862],{"type":48,"value":863}," @sentry\u002Fjunior",{"type":43,"tag":103,"props":865,"children":866},{"style":116},[867],{"type":48,"value":868}," exec",{"type":43,"tag":103,"props":870,"children":871},{"style":116},[872],{"type":48,"value":873}," vitest",{"type":43,"tag":103,"props":875,"children":876},{"style":116},[877],{"type":48,"value":878}," run",{"type":43,"tag":103,"props":880,"children":881},{"style":116},[882],{"type":48,"value":883}," tests\u002Fintegration\u002Flocal-agent-runner.test.ts\n",{"type":43,"tag":103,"props":885,"children":886},{"class":105,"line":290},[887,891,895,899,903,907,911],{"type":43,"tag":103,"props":888,"children":889},{"style":110},[890],{"type":48,"value":113},{"type":43,"tag":103,"props":892,"children":893},{"style":116},[894],{"type":48,"value":858},{"type":43,"tag":103,"props":896,"children":897},{"style":116},[898],{"type":48,"value":863},{"type":43,"tag":103,"props":900,"children":901},{"style":116},[902],{"type":48,"value":868},{"type":43,"tag":103,"props":904,"children":905},{"style":116},[906],{"type":48,"value":873},{"type":43,"tag":103,"props":908,"children":909},{"style":116},[910],{"type":48,"value":878},{"type":43,"tag":103,"props":912,"children":913},{"style":116},[914],{"type":48,"value":915}," tests\u002Fintegration\u002Foauth-callback.test.ts\n",{"type":43,"tag":103,"props":917,"children":918},{"class":105,"line":720},[919,923,927,931,935,939,943,948],{"type":43,"tag":103,"props":920,"children":921},{"style":110},[922],{"type":48,"value":113},{"type":43,"tag":103,"props":924,"children":925},{"style":116},[926],{"type":48,"value":858},{"type":43,"tag":103,"props":928,"children":929},{"style":116},[930],{"type":48,"value":863},{"type":43,"tag":103,"props":932,"children":933},{"style":116},[934],{"type":48,"value":868},{"type":43,"tag":103,"props":936,"children":937},{"style":116},[938],{"type":48,"value":873},{"type":43,"tag":103,"props":940,"children":941},{"style":116},[942],{"type":48,"value":878},{"type":43,"tag":103,"props":944,"children":945},{"style":116},[946],{"type":48,"value":947}," tests\u002Fintegration\u002Fmcp-oauth-callback.test.ts",{"type":43,"tag":103,"props":949,"children":950},{"style":116},[951],{"type":48,"value":952}," tests\u002Fintegration\u002Fmcp-auth-runtime-slack.test.ts\n",{"type":43,"tag":44,"props":954,"children":955},{},[956,958,964,966,972,974,980,982,988,990,996,998,1003,1005,1011,1013,1019],{"type":48,"value":957},"For SQL conversation storage changes, verify the resumed turn rebuilds context\nfrom SQL, not ",{"type":43,"tag":51,"props":959,"children":961},{"className":960},[],[962],{"type":48,"value":963},"thread-state",{"type":48,"value":965}," mirrors: conversation context must hydrate from\n",{"type":43,"tag":51,"props":967,"children":969},{"className":968},[],[970],{"type":48,"value":971},"junior_conversation_messages",{"type":48,"value":973}," (",{"type":43,"tag":51,"props":975,"children":977},{"className":976},[],[978],{"type":48,"value":979},"hydrateConversationMessages",{"type":48,"value":981},") and pi history\nfrom ",{"type":43,"tag":51,"props":983,"children":985},{"className":984},[],[986],{"type":48,"value":987},"junior_conversation_events",{"type":48,"value":989}," through the Pi adapter (",{"type":43,"tag":51,"props":991,"children":993},{"className":992},[],[994],{"type":48,"value":995},"loadProjection",{"type":48,"value":997},"). In\nthose tests, transcripts seeded only into ",{"type":43,"tag":51,"props":999,"children":1001},{"className":1000},[],[1002],{"type":48,"value":963},{"type":48,"value":1004}," must also be persisted\nto SQL (",{"type":43,"tag":51,"props":1006,"children":1008},{"className":1007},[],[1009],{"type":48,"value":1010},"persistConversationMessages",{"type":48,"value":1012},") before the callback runs, and the\nresumed agent-run input ",{"type":43,"tag":51,"props":1014,"children":1016},{"className":1015},[],[1017],{"type":48,"value":1018},"conversationContext",{"type":48,"value":1020}," must contain the SQL-seeded\nmessages.",{"type":43,"tag":73,"props":1022,"children":1024},{"id":1023},"failure-handling",[1025],{"type":48,"value":1026},"Failure Handling",{"type":43,"tag":44,"props":1028,"children":1029},{},[1030,1032,1038,1040,1045,1047,1052,1054,1060,1062,1068,1070,1075],{"type":48,"value":1031},"If local chat fails because credentials are missing or expired, refresh the\nenvironment when appropriate with ",{"type":43,"tag":51,"props":1033,"children":1035},{"className":1034},[],[1036],{"type":48,"value":1037},"pnpm dev:env",{"type":48,"value":1039},", then rerun the same command.\nIf local chat fails with a ",{"type":43,"tag":51,"props":1041,"children":1043},{"className":1042},[],[1044],{"type":48,"value":971},{"type":48,"value":1046}," or\n",{"type":43,"tag":51,"props":1048,"children":1050},{"className":1049},[],[1051],{"type":48,"value":987},{"type":48,"value":1053}," query error, the local Postgres schema predates the\nSQL conversation storage cutover; run ",{"type":43,"tag":51,"props":1055,"children":1057},{"className":1056},[],[1058],{"type":48,"value":1059},"pnpm cli -- upgrade",{"type":48,"value":1061},", then rerun.\nIf Redis errors appear during ordinary local QA, check whether\n",{"type":43,"tag":51,"props":1063,"children":1065},{"className":1064},[],[1066],{"type":48,"value":1067},"JUNIOR_STATE_ADAPTER=redis",{"type":48,"value":1069}," was set; local chat normally defaults to memory\nstate.\nIf OAuth returns ",{"type":43,"tag":51,"props":1071,"children":1073},{"className":1072},[],[1074],{"type":48,"value":784},{"type":48,"value":1076},", verify port 3000 is listening and remove stale duplicate\ndev servers or tunnel clients before retrying. If the provider says the\nauthorization expired, discard that URL and start a fresh chat attempt after\nthe callback health checks pass.",{"type":43,"tag":44,"props":1078,"children":1079},{},[1080],{"type":48,"value":1081},"If the model answer is too loose to prove the behavior, use a narrower prompt,\nan exact-output prompt, interactive mode, or a direct plugin CLI command. If the\nbehavior cannot be exercised through the local client\u002Fagent, say local QA is\ninsufficient and name the runtime surface that still needs manual coverage.",{"type":43,"tag":73,"props":1083,"children":1085},{"id":1084},"reporting",[1086],{"type":48,"value":1087},"Reporting",{"type":43,"tag":44,"props":1089,"children":1090},{},[1091],{"type":48,"value":1092},"Report:",{"type":43,"tag":436,"props":1094,"children":1095},{},[1096,1109,1114,1119,1131],{"type":43,"tag":440,"props":1097,"children":1098},{},[1099,1101,1107],{"type":48,"value":1100},"the exact ",{"type":43,"tag":51,"props":1102,"children":1104},{"className":1103},[],[1105],{"type":48,"value":1106},"pnpm cli -- ...",{"type":48,"value":1108}," commands run",{"type":43,"tag":440,"props":1110,"children":1111},{},[1112],{"type":48,"value":1113},"for dashboard mock QA, the dev-server command, URL, mock conversation or page\ninspected, and the visible UI evidence",{"type":43,"tag":440,"props":1115,"children":1116},{},[1117],{"type":48,"value":1118},"exit status and the key output that proves the behavior",{"type":43,"tag":440,"props":1120,"children":1121},{},[1122,1124,1129],{"type":48,"value":1123},"whether ",{"type":43,"tag":51,"props":1125,"children":1127},{"className":1126},[],[1128],{"type":48,"value":56},{"type":48,"value":1130}," loaded the expected app\u002Fplugin\u002Fskill path",{"type":43,"tag":440,"props":1132,"children":1133},{},[1134],{"type":48,"value":1135},"whether local QA was sufficient, or what remains unproven locally",{"type":43,"tag":44,"props":1137,"children":1138},{},[1139],{"type":48,"value":1140},"Keep any automated test\u002Flint\u002Ftypecheck\u002Feval results in a separate validation\nsection so they are not confused with local QA.",{"type":43,"tag":1142,"props":1143,"children":1144},"style",{},[1145],{"type":48,"value":1146},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":1148,"total":1320},[1149,1170,1184,1197,1211,1228,1244,1258,1268,1279,1289,1307],{"slug":1150,"name":1150,"fn":1151,"description":1152,"org":1153,"tags":1154,"stars":1167,"repoUrl":1168,"updatedAt":1169},"xcodebuildmcp","build and test Apple apps with XcodeBuildMCP","Official skill for XcodeBuildMCP. Use when doing iOS\u002FmacOS\u002FwatchOS\u002FtvOS\u002FvisionOS work (build, test, run, debug, log, UI automation).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1155,1156,1159,1162,1163,1164],{"name":24,"slug":25,"type":16},{"name":1157,"slug":1158,"type":16},"iOS","ios",{"name":1160,"slug":1161,"type":16},"macOS","macos",{"name":9,"slug":8,"type":16},{"name":21,"slug":22,"type":16},{"name":1165,"slug":1166,"type":16},"Xcode","xcode",6176,"https:\u002F\u002Fgithub.com\u002Fgetsentry\u002FXcodeBuildMCP","2026-04-06T18:13:34.8719",{"slug":1171,"name":1171,"fn":1172,"description":1173,"org":1174,"tags":1175,"stars":1167,"repoUrl":1168,"updatedAt":1183},"xcodebuildmcp-cli","build and test Apple apps via CLI","Official skill for the XcodeBuildMCP CLI. Use when doing iOS\u002FmacOS\u002FwatchOS\u002FtvOS\u002FvisionOS work (build, test, run, debug, log, UI automation).",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1176,1179,1180,1181,1182],{"name":1177,"slug":1178,"type":16},"CLI","cli",{"name":1157,"slug":1158,"type":16},{"name":1160,"slug":1161,"type":16},{"name":21,"slug":22,"type":16},{"name":1165,"slug":1166,"type":16},"2026-04-06T18:13:36.13414",{"slug":1185,"name":1185,"fn":1186,"description":1187,"org":1188,"tags":1189,"stars":1194,"repoUrl":1195,"updatedAt":1196},"agents-md","maintain project instruction files","Creates and maintains concise AGENTS.md and CLAUDE.md project instruction files. Use when asked to create AGENTS.md, update AGENTS.md, maintain agent docs, set up CLAUDE.md, document repository agent conventions, or keep coding-agent instructions minimal and reference-backed.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1190,1193],{"name":1191,"slug":1192,"type":16},"Documentation","documentation",{"name":18,"slug":19,"type":16},861,"https:\u002F\u002Fgithub.com\u002Fgetsentry\u002Fskills","2026-05-15T06:16:29.695991",{"slug":1198,"name":1198,"fn":1199,"description":1200,"org":1201,"tags":1202,"stars":1194,"repoUrl":1195,"updatedAt":1210},"blog-writing-guide","write and review engineering blog posts","Write, review, and improve blog posts for the Sentry engineering blog following Sentry's specific writing standards, voice, and quality bar. Use this skill whenever someone asks to write a blog post, draft a technical article, review blog content, improve a draft, write a product announcement, create an engineering deep-dive, or produce any written content destined for the Sentry blog or developer audience. Also trigger when the user mentions \"blog post,\" \"blog draft,\" \"write-up,\" \"announcement post,\" \"engineering post,\" \"deep dive,\" \"postmortem,\" or asks for help with technical writing for Sentry. Even if the user just says \"help me write about [feature\u002Ftopic]\" — if it sounds like it could become a Sentry blog post, use this skill.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1203,1206,1207],{"name":1204,"slug":1205,"type":16},"Communications","communications",{"name":9,"slug":8,"type":16},{"name":1208,"slug":1209,"type":16},"Technical Writing","technical-writing","2026-05-15T06:16:33.38217",{"slug":1212,"name":1212,"fn":1213,"description":1214,"org":1215,"tags":1216,"stars":1194,"repoUrl":1195,"updatedAt":1227},"brand-guidelines","write copy following Sentry brand guidelines","Write copy following Sentry brand guidelines. Use when writing UI text, error messages, empty states, onboarding flows, 404 pages, documentation, marketing copy, or any user-facing content. Covers both Plain Speech (default) and Sentry Voice tones.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1217,1220,1223,1224],{"name":1218,"slug":1219,"type":16},"Branding","branding",{"name":1221,"slug":1222,"type":16},"Content Creation","content-creation",{"name":9,"slug":8,"type":16},{"name":1225,"slug":1226,"type":16},"UX Copy","ux-copy","2026-05-15T06:16:22.395707",{"slug":1229,"name":1229,"fn":1230,"description":1231,"org":1232,"tags":1233,"stars":1194,"repoUrl":1195,"updatedAt":1243},"claude-settings-audit","generate Claude Code settings permissions","Analyze a repository to generate recommended Claude Code settings.json permissions. Use when setting up a new project, auditing existing settings, or determining which read-only bash commands to allow. Detects tech stack, build tools, and monorepo structure.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1234,1237,1240],{"name":1235,"slug":1236,"type":16},"Claude Code","claude-code",{"name":1238,"slug":1239,"type":16},"Configuration","configuration",{"name":1241,"slug":1242,"type":16},"Security","security","2026-05-15T06:16:44.335977",{"slug":1245,"name":1245,"fn":1246,"description":1247,"org":1248,"tags":1249,"stars":1194,"repoUrl":1195,"updatedAt":1257},"code-review","perform code reviews for Sentry projects","Perform code reviews following Sentry engineering practices. Use when reviewing pull requests, examining code changes, or providing feedback on code quality. Covers security, performance, testing, and design review.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1250,1252,1253,1256],{"name":1251,"slug":1245,"type":16},"Code Review",{"name":18,"slug":19,"type":16},{"name":1254,"slug":1255,"type":16},"Performance","performance",{"name":1241,"slug":1242,"type":16},"2026-05-15T06:16:35.824864",{"slug":1259,"name":1259,"fn":1260,"description":1261,"org":1262,"tags":1263,"stars":1194,"repoUrl":1195,"updatedAt":1267},"code-simplifier","simplify and refine source code","Simplifies and refines code for clarity, consistency, and maintainability while preserving all functionality. Use when asked to \"simplify code\", \"clean up code\", \"refactor for clarity\", \"improve readability\", or review recently modified code for elegance. Focuses on project-specific best practices.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1264],{"name":1265,"slug":1266,"type":16},"Code Analysis","code-analysis","2026-05-15T06:16:32.127981",{"slug":1269,"name":1269,"fn":1270,"description":1271,"org":1272,"tags":1273,"stars":1194,"repoUrl":1195,"updatedAt":1278},"commit","create commits with Sentry conventions","Use for every request to commit changes or draft a commit message. Creates Sentry-style conventional commits with issue references.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1274,1277],{"name":1275,"slug":1276,"type":16},"Git","git",{"name":9,"slug":8,"type":16},"2026-07-18T05:15:10.723937",{"slug":1280,"name":1280,"fn":1281,"description":1282,"org":1283,"tags":1284,"stars":1194,"repoUrl":1195,"updatedAt":1288},"create-branch","create git branches for Sentry workflows","Create a git branch following Sentry naming conventions. Use when asked to \"create a branch\", \"new branch\", \"start a branch\", \"make a branch\", \"switch to a new branch\", or when starting new work on the default branch.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1285,1286,1287],{"name":18,"slug":19,"type":16},{"name":1275,"slug":1276,"type":16},{"name":9,"slug":8,"type":16},"2026-05-15T06:16:39.458431",{"slug":1290,"name":1290,"fn":1291,"description":1292,"org":1293,"tags":1294,"stars":1194,"repoUrl":1195,"updatedAt":1306},"django-access-review","review Django access control and IDOR","Django access control and IDOR security review. Use when reviewing Django views, DRF viewsets, ORM queries, or any Python\u002FDjango code handling user authorization. Trigger keywords: \"IDOR\", \"access control\", \"authorization\", \"Django permissions\", \"object permissions\", \"tenant isolation\", \"broken access\".",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1295,1298,1299,1302,1305],{"name":1296,"slug":1297,"type":16},"Access Control","access-control",{"name":1265,"slug":1266,"type":16},{"name":1300,"slug":1301,"type":16},"Django","django",{"name":1303,"slug":1304,"type":16},"Python","python",{"name":1241,"slug":1242,"type":16},"2026-05-15T06:16:43.098698",{"slug":1308,"name":1308,"fn":1309,"description":1310,"org":1311,"tags":1312,"stars":1194,"repoUrl":1195,"updatedAt":1319},"django-perf-review","review and optimize Django performance","Django performance code review. Use when asked to \"review Django performance\", \"find N+1 queries\", \"optimize Django\", \"check queryset performance\", \"database performance\", \"Django ORM issues\", or audit Django code for performance problems.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1313,1314,1317,1318],{"name":1251,"slug":1245,"type":16},{"name":1315,"slug":1316,"type":16},"Database","database",{"name":1300,"slug":1301,"type":16},{"name":1254,"slug":1255,"type":16},"2026-05-15T06:16:24.832813",88,{"items":1322,"total":1410},[1323,1340,1358,1373,1390,1397],{"slug":1324,"name":1324,"fn":1325,"description":1326,"org":1327,"tags":1328,"stars":26,"repoUrl":27,"updatedAt":1339},"amplitude","query Amplitude product analytics","Query read-only Amplitude product analytics. Use when users ask about active users, product usage, events, segmentation, funnels, conversion, retention, charts, dashboards, experiments, cohorts, taxonomy, session replay, feature flags, guides, surveys, feedback, agent analytics, or individual user activity in Amplitude. Do not use for changing Amplitude charts, dashboards, experiments, cohorts, flags, taxonomy, or project configuration.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1329,1332,1335,1338],{"name":1330,"slug":1331,"type":16},"Analytics","analytics",{"name":1333,"slug":1334,"type":16},"Charts","charts",{"name":1336,"slug":1337,"type":16},"Dashboards","dashboards",{"name":1087,"slug":1084,"type":16},"2026-07-11T05:53:26.659115",{"slug":1341,"name":1341,"fn":1342,"description":1343,"org":1344,"tags":1345,"stars":26,"repoUrl":27,"updatedAt":1357},"cloudflare","investigate Cloudflare production operations","Cloudflare production operations via the Cloudflare API MCP server. Use when users ask to investigate Workers errors or performance, check build or deployment status, query logs, inspect DNS records, check load balancer pool health, review Zero Trust tunnels, or manage Cloudflare resources. Do not use for Sentry issues, GitHub\u002FLinear ticketing, or non-Cloudflare infrastructure.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1346,1348,1351,1354],{"name":1347,"slug":1341,"type":16},"Cloudflare",{"name":1349,"slug":1350,"type":16},"Deployment","deployment",{"name":1352,"slug":1353,"type":16},"Monitoring","monitoring",{"name":1355,"slug":1356,"type":16},"Observability","observability","2026-07-01T07:46:37.892035",{"slug":1359,"name":1359,"fn":1360,"description":1361,"org":1362,"tags":1363,"stars":26,"repoUrl":27,"updatedAt":1372},"datadog","query Datadog telemetry and investigate behavior","Query live Datadog telemetry (logs, metrics, traces, spans, monitors, incidents, dashboards, services, hosts) through Datadog's Pup CLI. Use when users ask to investigate production behavior in Datadog, including searching logs, checking monitor status, inspecting traces or spans, looking up incidents, finding services, or correlating metrics. Do not use it for Sentry issues, repository\u002Fsource-code work, or ticketing.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1364,1366,1367,1368,1369],{"name":1365,"slug":1359,"type":16},"Datadog",{"name":24,"slug":25,"type":16},{"name":1352,"slug":1353,"type":16},{"name":1355,"slug":1356,"type":16},{"name":1370,"slug":1371,"type":16},"SRE","sre","2026-04-18T04:45:22.733842",{"slug":1374,"name":1374,"fn":1375,"description":1376,"org":1377,"tags":1378,"stars":26,"repoUrl":27,"updatedAt":1389},"junior","build and update Junior plugins","Build, review, or update Junior extension skills and plugins. Use when users ask to create a Junior SKILL.md, app skill, plugin, plugin.yaml, packaged plugin, MCP-backed plugin, OAuth or credentialed plugin, or to validate Junior extension files. Do not use for ordinary Junior usage, provider workflows, generic code editing, or non-Junior agent-skill authoring.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1379,1382,1383,1386],{"name":1380,"slug":1381,"type":16},"Automation","automation",{"name":18,"slug":19,"type":16},{"name":1384,"slug":1385,"type":16},"MCP","mcp",{"name":1387,"slug":1388,"type":16},"Plugin Development","plugin-development","2026-07-31T06:23:36.591638",{"slug":4,"name":4,"fn":5,"description":6,"org":1391,"tags":1392,"stars":26,"repoUrl":27,"updatedAt":28},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1393,1394,1395,1396],{"name":24,"slug":25,"type":16},{"name":18,"slug":19,"type":16},{"name":14,"slug":15,"type":16},{"name":21,"slug":22,"type":16},{"slug":1398,"name":1398,"fn":1399,"description":1400,"org":1401,"tags":1402,"stars":26,"repoUrl":27,"updatedAt":1409},"vercel","debug Vercel deployments and logs","Query Vercel deployments, build logs, runtime logs, and deployment status through the Vercel CLI. Use when users ask to debug Vercel deployments, inspect failed builds, fetch production or preview runtime logs, find a deployment for a project or commit SHA, or investigate Vercel-hosted app errors. Do not use it for deploying, rolling back, changing project settings, domains, env vars, caches, storage, or any other Vercel mutation.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[1403,1404,1405,1406,1407],{"name":1177,"slug":1178,"type":16},{"name":24,"slug":25,"type":16},{"name":1349,"slug":1350,"type":16},{"name":1355,"slug":1356,"type":16},{"name":1408,"slug":1398,"type":16},"Vercel","2026-07-24T05:40:46.832412",6]