Skip to content

Single-source provider guides: bundled docs/guides catalog serving MCP, /guides pages, and raw text/markdown - #1255

Merged
kody-bot merged 8 commits into
mainfrom
cursor/provider-guides-d7c2
Aug 6, 2026
Merged

kody-bot merged 8 commits into
mainfrom
cursor/provider-guides-d7c2

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Aug 6, 2026 •

Copy link
Copy Markdown
Owner

Summary

Provider connect guides existed only as agent-improvised prompts ("walk me through creating my own OAuth app"), and coding_guide_get fetched docs/guides/*.md from raw.githubusercontent.com at request time. This PR makes docs/guides/ a single bundled source of truth served three ways, and adds five verified provider connect guides.

  • Guide catalog (packages/worker/src/guides/): every guide carries YAML frontmatter (id, title, summary, category, provider, lastVerified); markdown is imported at build time (same pattern as blog posts) so MCP, web, and raw-markdown responses always serve identical deployed content.
  • coding_guide_get now serves the bundled catalog — no request-time GitHub dependency; enum, per-guide descriptions, and search keywords derive from frontmatter. openapi_integrations becomes loadable for the first time.
  • Web pages /guides and /guides/:slug (blog-area chunk, SSR + .json twins), with a Guides link in the site header and footer.
  • Markdown content negotiation: /guides.md, /guides/:slug.md, /blog/:slug.md, plus Accept: text/markdown on the HTML routes (Vary: Accept; HTML wins ties so browsers are unaffected).
  • Five provider guides (docs/guides/providers/): Google, GitHub, Notion, Spotify, Discord — verified console steps (August 2026), prefilled /connect/oauth / /account/secrets/new links, personal-token lanes where they exist, minimal-scope tiers, execute smoke tests, and the sharp edges (Google's Testing-mode 7-day refresh-token trap, Spotify's Premium requirement, Discord's OAuth-vs-bot split, Gmail restricted scopes).
  • Surfacing: integrations-page suggestion cards gain "Setup guide" links and guide-first copyable prompts (plus a Notion card); the onboarding setup prompt points agents at provider_* guides; docs updated (docs/guides/README.md, docs/use/first-steps.md, docs/use/index.md). A parity test pins suggestion guideSlugs to real catalog entries.
  • UI primitives: markdown renderer gains an opt-in first-party link policy (root-relative links like /connect/oauth?..., user-scope paths still refused) and copyable code blocks (copy-code-block.tsx); the untrusted default is unchanged.

Supersedes #1254 (recreated non-draft so CI and review run).

Testing

  • npm run validate fully green (all 12 jobs: 1882 unit tests, 8 Playwright e2e, MCP e2e, lint/format/typecheck/docs checks).
  • New unit tests: frontmatter contract + catalog integrity, markdown negotiation, guide handlers, coding_guide_get serving every bundled guide, integration-suggestion ↔ catalog parity.
  • Manual dev-server verification of all four markdown lanes (.md twins, Accept: text/markdown, browser Accept → HTML, blog twin) and a recorded browser walkthrough.
  • The copy button's click → "Copied" cycle was additionally verified headless (with and without clipboard permission) after an automation false alarm — logs showed the interaction healthy end to end.

guides_pages_copy_button_and_integration_setup_links_walkthrough.mp4

guide_code_block_copy_button_copied_state.mp4

Guides index

Integration suggestion cards with Setup guide links

System recap — extends existing primitives (medium risk)

Mode: recap · Base: main @ 34614dc1 · Head: 00d3bf8d

Classification: extends — no new taxonomy primitive; app-ui gains routes/negotiation and capability-registry's coding_guide_get changes its content source from runtime GitHub fetch to the build-time guide catalog (new shared module packages/worker/src/guides/, plumbing under existing primitives).

Primitives touched

Primitive Group Impact
app-ui surfaces extends — /guides routes, .md twins + Accept: text/markdown negotiation, first-party markdown links, copyable code blocks
capability-registry assistant extends — coding_guide_get serves the bundled catalog; enum/keywords derive from guide frontmatter
app-sessions auth composes — onboarding setup prompt copy only (onboarding-data.ts)

System map

Guide markdown flows from docs/guides/ through the bundled catalog into both the MCP capability and the web routes.

Legend: green = composes (wiring only) · amber = extended by this PR · red = new primitive · gray = context (unchanged, included only when an edge crosses it).

flowchart LR
	guides["docs/guides/*.md<br/>frontmatter + body"]:::touched
	catalog["guides catalog<br/>build-time bundle (#worker/guides)"]:::touched
	appUi["app-ui<br/>Browser app (Remix 3)"]:::extended
	capabilityRegistry["capability-registry<br/>Capability registry"]:::extended
	guides -->|"import at build time"| catalog
	catalog -->|"coding_guide_get body/title from frontmatter id"| capabilityRegistry
	catalog -->|"/guides + /guides/:slug SSR + .json"| appUi
	catalog -->|"/guides/:slug.md + Accept: text/markdown"| appUi
	appUi -->|"Setup guide links + guide-first prompts on /account/integrations"| catalog
	classDef touched fill:#1a7f37,color:#fff
	classDef extended fill:#9a6700,color:#fff
	classDef added fill:#cf222e,color:#fff
	classDef untouched fill:#57606a,color:#fff
Loading

Before / after

before: coding_guide_get -> fetch raw.githubusercontent.com/main/docs/guides/<file>.md (runtime network dependency)
after:  coding_guide_get -> bundled guide catalog (deployed content, no network); web + raw markdown serve the same bundle

before: GET /guides -> 404
after:  GET /guides | /guides.json | /guides.md | /guides/:slug | .json | .md ; blog posts gain /blog/:slug.md

Invariants

Per-user isolation untouched: guides are static repo content with no user data; the untrusted markdown link policy (user-scope refusal) stays the default and applies under the first-party policy too.

Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features

    • Added a Guides experience with platform and provider setup documentation.
    • Added detailed guides for Discord, GitHub, Google, Notion, and Spotify.
    • Guides are available through the website, raw Markdown, APIs, and MCP.
    • Added provider-specific setup links in integrations and onboarding.
    • Added copy buttons for code examples and improved Markdown navigation.
    • Added Markdown responses for blog posts and guides.
  • Documentation

    • Expanded credentials guidance and guide navigation.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@cursor[bot], you've reached your PR review limit, so we couldn't start this review.

Next review available in: 24 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c8f8a261-43c3-4037-ba8c-509700b17e51

📥 Commits

Reviewing files that changed from the base of the PR and between 2ea220c and a879f35.

📒 Files selected for processing (11)
  • docs/guides/providers/discord.md
  • docs/guides/providers/github.md
  • docs/guides/providers/google.md
  • docs/guides/providers/notion.md
  • docs/guides/providers/spotify.md
  • packages/worker/src/app/handlers/blog.tsx
  • packages/worker/src/app/handlers/guides.tsx
  • packages/worker/src/app/markdown-negotiation.node.test.ts
  • packages/worker/src/app/markdown-negotiation.ts
  • packages/worker/src/guides/rewrite-relative-links.node.test.ts
  • packages/worker/src/guides/rewrite-relative-links.ts
📝 Walkthrough

Walkthrough

The pull request adds a build-time guide catalog with YAML metadata, provider setup documentation, HTML/JSON/Markdown delivery, MCP lookup, web guide pages, copyable code blocks, and provider-specific setup links.

Changes

Guide catalog and content

Layer / File(s) Summary
Guide metadata, parsing, and catalog
docs/guides/*, docs/guides/providers/*, packages/worker/src/guides/*
Guide frontmatter and provider walkthroughs are added. The worker parses, validates, indexes, sorts, rewrites links, and summarizes bundled guides.
Guide HTTP and Markdown delivery
packages/worker/src/app/handlers/*, packages/worker/src/app/routes.ts, packages/worker/src/app/router.ts, packages/worker/src/app/loader-data.ts, packages/worker/src/app/markdown-negotiation.ts
Guide index and detail endpoints serve HTML, JSON, and Markdown. Blog posts also support Markdown responses.
Web guide browsing
packages/worker/client/routes/guides.tsx, packages/worker/client/routes/guide-detail.tsx, packages/worker/client/markdown-view.tsx, packages/worker/client/copy-code-block.tsx
The client adds guide index and detail pages, first-party link handling, copyable code blocks, loading and error states, and raw Markdown/MCP links.
Provider setup integration
packages/worker/client/routes/integration-provider-catalog.ts, packages/worker/client/routes/account-integrations.tsx, packages/worker/src/app/onboarding-data.ts, docs/use/*
Provider entries can reference setup guides. Provider cards, setup prompts, onboarding text, and credentials guidance use those references.
Bundled MCP capability
packages/worker/src/mcp/capabilities/coding/kody-official-guide.ts
The MCP capability loads guide content from the bundled catalog instead of fetching GitHub content at request time. It derives metadata and rejects unknown guide IDs.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Visitor
  participant GuidesRoute
  participant GuideApi
  participant GuideCatalog
  participant MarkdownView

  Visitor->>GuidesRoute: Open /guides
  GuidesRoute->>GuideApi: Request guide summaries
  GuideApi->>GuideCatalog: List bundled guides
  GuideCatalog-->>GuideApi: Return metadata
  GuideApi-->>GuidesRoute: Return JSON
  GuidesRoute-->>Visitor: Render grouped guide links
  Visitor->>MarkdownView: Open a guide
  MarkdownView-->>Visitor: Render Markdown and copyable code
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the bundled provider-guide catalog and its MCP, web, and Markdown delivery surfaces.
Description check ✅ Passed The description provides detailed change summaries, testing evidence, and system impact; the intent is clear from the opening summary.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/provider-guides-d7c2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 00d3bf8. Configure here.

Comment thread packages/worker/client/markdown-view.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
packages/worker/client/routes/integration-provider-catalog.node.test.ts (1)

8-24: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Strengthen the guide parity test.

The test checks only that a provider identifier appears in the prompt. It can pass if expected provider mappings are removed or if the guide load, minimal-access, save, or smoke-test instructions regress. Assert the intended provider-to-slug mappings and the guide-specific wording, including the absence of generic OAuth-app instructions.

Proposed assertions
 	const guideBacked = integrationProviderSuggestions.filter(
 		(provider) => provider.guideSlug,
 	)
-	expect(guideBacked.length).toBeGreaterThan(0)
+	expect(
+		new Set(guideBacked.map((provider) => `${provider.id}:${provider.guideSlug}`)),
+	).toEqual(
+		new Set([
+			'github:github',
+			'google:google',
+			'notion:notion',
+			'spotify:spotify',
+			'discord:discord',
+		]),
+	)

 	for (const provider of guideBacked) {
 		// existing catalog assertions
 		const prompt = buildIntegrationSetupPrompt(provider)
 		expect(prompt).toContain(`provider_${provider.guideSlug}`)
+		expect(prompt).toContain('Load the official Kody setup guide')
+		expect(prompt).toContain('smoke test')
+		expect(prompt).not.toContain('creating my own OAuth app')
 	}

The PR objective defines five verified provider guides and guide-backed setup prompts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/client/routes/integration-provider-catalog.node.test.ts`
around lines 8 - 24, Strengthen the test around integrationProviderSuggestions,
getGuideBySlug, and buildIntegrationSetupPrompt to verify the five expected
provider-to-guide slug mappings explicitly. For each mapped provider, assert the
prompt contains guide-specific wording covering guide loading, minimal access,
saving, and smoke testing, and assert generic OAuth-app instructions are absent;
retain the existing guide category validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/guides/providers/github.md`:
- Around line 71-74: Update the GitHub OAuth token lifecycle documentation to
state that OAuth App tokens are automatically revoked after one year of API
inactivity, despite having no fixed expiration. Add guidance to reconnect the
saved secret using a fresh OAuth grant when authentication fails or an
inactivity-expiration error occurs, while preserving the existing refresh-token
and manual-revocation details.

In `@docs/guides/providers/spotify.md`:
- Around line 35-44: Update the Spotify Development Mode guidance to state that
new developers can create only one client ID. In the refresh-token guidance,
explain that rotation may omit a replacement token, so retain the existing token
when none is returned; note that tokens expire six months after authorization
and instruct users to reauthorize after invalid_grant, reflecting the rules
active as of August 6, 2026.

In `@packages/worker/src/app/handlers/guides.tsx`:
- Around line 47-58: Update the negotiated response handling in the guides
handler, including the renderAppPage branches around the referenced flow, to
ensure every HTML response includes Vary: Accept while preserving any existing
Vary header values. Reuse the response/header mechanism already used by
renderAppPage rather than replacing other headers.

In `@packages/worker/src/app/markdown-negotiation.ts`:
- Around line 18-37: Update prefersMarkdown to apply text/* and */* quality
values to both Markdown and HTML while resolving each representation by
media-range specificity. Track exact, type-wildcard, and global wildcard
qualities separately so an exact q=0 overrides less-specific ranges; preserve
the existing return comparison using the resolved qualities.

---

Nitpick comments:
In `@packages/worker/client/routes/integration-provider-catalog.node.test.ts`:
- Around line 8-24: Strengthen the test around integrationProviderSuggestions,
getGuideBySlug, and buildIntegrationSetupPrompt to verify the five expected
provider-to-guide slug mappings explicitly. For each mapped provider, assert the
prompt contains guide-specific wording covering guide loading, minimal access,
saving, and smoke testing, and assert generic OAuth-app instructions are absent;
retain the existing guide category validation.
🪄 Autofix

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d548b6f3-9df9-452b-aa43-c88fe5bd6827

📥 Commits

Reviewing files that changed from the base of the PR and between 915b12a and 00d3bf8.

📒 Files selected for processing (46)
  • docs/guides/README.md
  • docs/guides/account-package-invocation-token-setup.md
  • docs/guides/account-secret-setup.md
  • docs/guides/integration-backed-app-happy-path.md
  • docs/guides/integration-bootstrap.md
  • docs/guides/oauth.md
  • docs/guides/openapi-integrations.md
  • docs/guides/package-authoring.md
  • docs/guides/package-lifecycle.md
  • docs/guides/package-service-pattern.md
  • docs/guides/package-subscriptions.md
  • docs/guides/platform-friction.md
  • docs/guides/providers/discord.md
  • docs/guides/providers/github.md
  • docs/guides/providers/google.md
  • docs/guides/providers/notion.md
  • docs/guides/providers/spotify.md
  • docs/guides/secret-backed-integration.md
  • docs/use/first-steps.md
  • docs/use/index.md
  • packages/worker/client/copy-code-block.tsx
  • packages/worker/client/lazy-route.tsx
  • packages/worker/client/markdown-view.tsx
  • packages/worker/client/routes/account-integrations.tsx
  • packages/worker/client/routes/blog-area.ts
  • packages/worker/client/routes/guide-detail.tsx
  • packages/worker/client/routes/guides.tsx
  • packages/worker/client/routes/index.tsx
  • packages/worker/client/routes/integration-provider-catalog.node.test.ts
  • packages/worker/client/routes/integration-provider-catalog.ts
  • packages/worker/client/site-footer.tsx
  • packages/worker/client/site-header.tsx
  • packages/worker/src/app/handlers/blog.tsx
  • packages/worker/src/app/handlers/guides.node.test.ts
  • packages/worker/src/app/handlers/guides.tsx
  • packages/worker/src/app/loader-data.ts
  • packages/worker/src/app/markdown-negotiation.node.test.ts
  • packages/worker/src/app/markdown-negotiation.ts
  • packages/worker/src/app/onboarding-data.ts
  • packages/worker/src/app/router.ts
  • packages/worker/src/app/routes.ts
  • packages/worker/src/guides/catalog.node.test.ts
  • packages/worker/src/guides/catalog.ts
  • packages/worker/src/guides/parse-frontmatter.ts
  • packages/worker/src/mcp/capabilities/coding/kody-official-guide.node.test.ts
  • packages/worker/src/mcp/capabilities/coding/kody-official-guide.ts

Comment thread docs/guides/providers/github.md Outdated
Comment on lines +71 to +74
GitHub supports S256 PKCE and recommends it, but PKCE does not replace the
client secret — the secret is still required at the token endpoint, so the Kody
flow is `confidential`. OAuth App tokens do not expire and there are no refresh
tokens; revoke the grant from GitHub settings to kill a token.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate file =="
git ls-files | grep -F 'docs/guides/providers/github.md' || true

echo "== relevant lines =="
if [ -f docs/guides/providers/github.md ]; then
  nl -ba docs/guides/providers/github.md | sed -n '55,85p'
fi

echo "== nearby token lifecycle mentions =="
rg -n "expire|revok|refresh|OAuth App|confidential|perman|token" docs/guides/providers/github.md .github README.md 2>/dev/null | head -120 || true

echo "== deterministic check: does current snippet imply permanent tokens? =="
python3 - <<'PY'
from pathlib import Path
p=Path('docs/guides/providers/github.md')
if p.exists():
    text=p.read_text()
    print("contains OAuth App tokens do not expire:", "OAuth App tokens do not expire" in text)
    print("contains refresh tokens:", "refresh tokens" in text)
PY

echo "== public docs availability probe =="
python3 - <<'PY'
import urllib.request, ssl
url="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/token-expiration-and-revocation"
ctx=ssl.create_default_context()
try:
    with urllib.request.urlopen(url, timeout=20, context=ctx) as r:
        print("status", r.status)
        # Search for relevant inactivity revocation phrasing.
        data=r.read(50000).decode("utf-8", errors="replace")
        hits=['after one year', 'one year', 'inactive', 'OAuth', 'OAuth App', 'no longer valid']
        for h in hits:
            print(f"{h}: {h.lower() in data.lower()}")
        # Print compact excerpt around first 'one year'.
        idx=data.lower().find('one year')
        if idx != -1:
            print("excerpt:")
            print(data[max(0,idx-500):idx+700])
except Exception as e:
    print("probe_failed", repr(e))
PY

Repository: kentcdodds/kody

Length of output: 264


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== relevant lines =="
if [ -f docs/guides/providers/github.md ]; then
  awk '{printf "%6d\t%s\n", NR, $0}' docs/guides/providers/github.md | sed -n '55,85p'
fi

echo "== nearby token lifecycle mentions =="
rg -n "expire|revok|refresh|OAuth App|confidential|perman|token" docs/guides/providers/github.md .github README.md 2>/dev/null | head -120 || true

echo "== deterministic check: does current snippet imply permanent tokens? =="
python3 - <<'PY'
from pathlib import Path
p=Path('docs/guides/providers/github.md')
if p.exists():
    text=p.read_text()
    print("contains OAuth App tokens do not expire:", "OAuth App tokens do not expire" in text)
    print("contains refresh tokens:", "refresh tokens" in text)
PY

echo "== public docs availability probe =="
python3 - <<'PY'
import urllib.request, ssl
url="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/token-expiration-and-revocation"
ctx=ssl.create_default_context()
try:
    with urllib.request.urlopen(url, timeout=20, context=ctx) as r:
        print("status", r.status)
        data=r.read(50000).decode("utf-8", errors="replace")
        hits=['after one year', 'one year', 'inactive', 'OAuth', 'OAuth App', 'no longer valid']
        for h in hits:
            print(f"{h}: {h.lower() in data.lower()}")
        idx=data.lower().find('one year')
        if idx != -1:
            print("excerpt:")
            print(data[max(0,idx-500):idx+700].replace('\n', ' '))
except Exception as e:
    print("probe_failed", repr(e))
PY

Repository: kentcdodds/kody

Length of output: 6583


🌐 Web query:

GitHub OAuth App tokens no longer valid after one year of inactivity token expiration revocation

💡 Result:

GitHub automatically revokes OAuth app access tokens and personal access tokens if they have not been used for one year [1][2]. This security measure is designed to limit the impact of potentially exposed tokens that are no longer actively required [1][2]. Key details regarding GitHub token inactivity and expiration include: - Scope of Inactivity Revocation: This one-year inactivity policy applies to both OAuth app access tokens and personal access tokens [1][2]. - Automatic Revocation: Once a token reaches the one-year threshold of inactivity, it is automatically revoked by GitHub and cannot be restored [1][2]. If the application or service requires continued access, a new token must be generated [1][2]. - Distinction from GitHub App Tokens: It is important to distinguish these from GitHub App user access tokens, which operate under a different lifecycle. By default, GitHub App user access tokens expire after eight hours and utilize refresh tokens for renewal [3][4]. - Token Limits: For OAuth apps, GitHub maintains a limit of ten active tokens per user/application/scope combination [5][1]. If an application exceeds this limit, the oldest tokens are automatically revoked to make room for new ones [5][1]. - Manual Revocation: Users can manually revoke access for any authorized OAuth app at any time through their personal account settings, which will invalidate all tokens associated with that app [6]. For more information on managing credentials, you can refer to GitHub's official documentation on token expiration and revocation [1][2].

Citations:


🌐 Web query:

site:docs.github.com "OAuth App" "do not expire" "one year"

💡 Result:

In the context of GitHub, OAuth tokens do not have a fixed one-year expiration simply by existing, but they are subject to automatic revocation if they remain unused for one year [1][2]. Specifically, GitHub automatically revokes an OAuth token or personal access token if it has not been used to authenticate requests for a period of one year [1][3][2]. This is a security measure designed to ensure that inactive credentials do not remain valid indefinitely [1]. It is important to distinguish between different credential types on GitHub, as they have different lifecycle policies: - OAuth app access tokens: These are generally long-lived but are revoked automatically if unused for one year [3]. - GitHub App user access tokens: These are short-lived by default (expiring after 8 hours) and require the use of a refresh token (which expires after 6 months) [4][5]. Owners can configure these to never expire, though this is not recommended [1][2]. - Personal access tokens (fine-grained): These have configurable expiration dates, up to a maximum of one year, or can be set to never expire [3]. In summary, while an OAuth app token is not designed to expire after exactly one year of its own accord, the one-year mark serves as a threshold for automatic revocation due to inactivity [1][3][2].

Citations:


Document GitHub’s one-year inactivity revocation for OAuth App tokens.

OAuth App tokens do not have a fixed lifetime, but GitHub revokes them automatically after one year without use through the API. If authentication fails or an expired inactivity error appears, reconnect the saved secret with a fresh OAuth grant.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/guides/providers/github.md` around lines 71 - 74, Update the GitHub
OAuth token lifecycle documentation to state that OAuth App tokens are
automatically revoked after one year of API inactivity, despite having no fixed
expiration. Add guidance to reconnect the saved secret using a fresh OAuth grant
when authentication fails or an inactivity-expiration error occurs, while
preserving the existing refresh-token and manual-revocation details.

Comment on lines +35 to +44
- Since February 2026, Development Mode requires the app owner to hold Spotify
Premium. If Premium lapses, the app stops working until it is restored.
- New developers can create up to 25 client IDs.
- Some Web API endpoints are unavailable in Development Mode; see the
[February 2026 migration guide](https://developer.spotify.com/documentation/web-api/tutorials/february-2026-migration-guide)
for the endpoint list.
- Extended Quota Mode is only available to organizations with at least 250k
monthly active users — not a realistic path for individuals. Personal use
stays in Development Mode, which is fine for one user: the app owner can
always authorize their own app.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Correct the Spotify Development Mode and refresh-token guidance.

Line 37 states that new developers can create 25 client IDs. Spotify limits new Development Mode developers to one client ID.

Line 79 states that PKCE refresh tokens rotate on every refresh. A refresh response can omit a replacement token. Refresh tokens also expire six months after authorization. Tell users to retain the prior token when no replacement is returned and to reauthorize after invalid_grant. As of August 6, 2026, these rules are active. (developer.spotify.com)

Also applies to: 79-80

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/guides/providers/spotify.md` around lines 35 - 44, Update the Spotify
Development Mode guidance to state that new developers can create only one
client ID. In the refresh-token guidance, explain that rotation may omit a
replacement token, so retain the existing token when none is returned; note that
tokens expire six months after authorization and instruct users to reauthorize
after invalid_grant, reflecting the rules active as of August 6, 2026.

Comment thread packages/worker/src/app/handlers/guides.tsx Outdated
Comment thread packages/worker/src/app/markdown-negotiation.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/worker/src/guides/rewrite-relative-links.ts`:
- Line 41: Update the link-matching replacement in rewriteRelativeLinks to
recognize an optional Markdown link title after the destination, rewrite only
the destination, and preserve the title in the output. Add a regression case
covering a titled relative guide link such as `[OAuth](./oauth.md "OAuth
guide")` and verify it resolves correctly.
🪄 Autofix

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6a4f5bf0-e269-4ed5-800d-cda9fedbb70e

📥 Commits

Reviewing files that changed from the base of the PR and between 00d3bf8 and 2ea220c.

📒 Files selected for processing (4)
  • packages/worker/src/guides/catalog.node.test.ts
  • packages/worker/src/guides/catalog.ts
  • packages/worker/src/guides/rewrite-relative-links.node.test.ts
  • packages/worker/src/guides/rewrite-relative-links.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/worker/src/guides/catalog.node.test.ts
  • packages/worker/src/guides/catalog.ts

Comment thread packages/worker/src/guides/rewrite-relative-links.ts Outdated
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.

3 participants