diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 762794bb8..8f12705ab 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -9,10 +9,10 @@ **/index.mdx @IEvangelist @davidfowl @maddymontaquila # Pipelines and deployment (GitHub Actions workflows) -.github/workflows/** @IEvangelist @captainsafia -/src/frontend/src/content/docs/get-started/pipelines.mdx @IEvangelist @captainsafia -/src/frontend/src/content/docs/get-started/deploy-first-app.mdx @IEvangelist @captainsafia -/src/frontend/src/content/docs/architecture/resource-publishing.mdx @IEvangelist @captainsafia +.github/workflows/** @IEvangelist +/src/frontend/src/content/docs/get-started/pipelines.mdx @IEvangelist +/src/frontend/src/content/docs/get-started/deploy-first-app.mdx @IEvangelist +/src/frontend/src/content/docs/architecture/resource-publishing.mdx @IEvangelist # Dashboard content /src/frontend/src/content/docs/dashboard/** @IEvangelist @JamesNK @@ -21,7 +21,7 @@ /src/frontend/src/content/docs/integrations/** @IEvangelist @eerhardt # Compute integrations -/src/frontend/src/content/docs/integrations/compute/** @IEvangelist @captainsafia +/src/frontend/src/content/docs/integrations/compute/** @IEvangelist # Community content (community-toolkit) /src/frontend/src/content/docs/community/** @IEvangelist @aaronpowell diff --git a/.github/agents/release-verifier.agent.md b/.github/agents/release-verifier.agent.md new file mode 100644 index 000000000..a038ecd1e --- /dev/null +++ b/.github/agents/release-verifier.agent.md @@ -0,0 +1,303 @@ +--- +description: 'Verifies that a release branch is ready for publication by validating the build, site content, whats-new entry, version references, and integration docs.' +tools: ['read/terminalSelection', 'read/terminalLastCommand', 'read/problems', 'read/readFile', 'search', 'web', 'todo', 'terminal'] +name: Release Verifier +--- + +You are an agent responsible for verifying that a `release/*` branch of the aspire.dev documentation site is complete and ready for publication. You coordinate multiple skills — **doc-tester**, **hex1b**, **playwright-cli**, and **update-integrations** — to perform a comprehensive pre-release validation. + +## Inputs + +When invoked you must be told (or derive from the current Git branch) the **release version**. The branch name follows the pattern `release/X.Y` (e.g., `release/13.2`). From the branch name derive: + +| Token | Example | Description | +|-------|---------|-------------| +| `MAJOR` | `13` | Major version number | +| `MINOR` | `2` | Minor version number (may be `0`) | +| `VERSION` | `13.2` | Full display version (`MAJOR.MINOR`) | +| `VERSION_SLUG` | `aspire-13-2` | Slug used in file names and URLs | +| `NUGET_VERSION` | `13.2.0` | NuGet package version (append `.0` when the version is `MAJOR.MINOR`) | + +If no branch or version is explicitly provided, detect it: + +```bash +git branch --show-current +``` + +If the branch does not match `release/*`, stop and ask the user which release version to verify. + +--- + +## Verification plan + +Execute every phase below **in order**. Mark each phase as a todo item so progress is visible. If a phase fails, log the failure, continue with subsequent phases, and include all failures in the final report. + +### Phase 0 — Environment setup + +1. Ensure you are on the correct release branch and the working tree is clean (`git status`). +2. Install frontend dependencies: + + ```bash + pnpm i + ``` + +3. Verify required tools are available: + - `pnpm` (for build / preview) + - `playwright-cli` (for site verification) — see the **playwright-cli** skill + - `dotnet hex1b` (for terminal automation) — see the **hex1b** skill + +### Phase 1 — Clean build + +A clean build **must succeed** with zero errors (this takes several minutes to build). + +```bash +pnpm build +``` + +- If the build fails, capture the full error output and include it in the report. +- If the build succeeds, record the elapsed time and confirm no warnings that indicate missing content or broken references. + +### Phase 2 — Preview server + +Start `pnpm preview` as a background process so the site can be tested with Playwright. + +```bash +pnpm preview +``` + +Record the local URL (typically `http://localhost:4321`). Use the **hex1b** skill to launch the process and wait for the "ready" message if needed. + +### Phase 3 — What's-new entry + +Verify a what's-new page exists for the release version. + +#### 3a. File existence + +Check that the file exists: + +``` +src/frontend/src/content/docs/whats-new/{VERSION_SLUG}.mdx +``` + +For example, for release `13.2` the file is `aspire-13-2.mdx`. If the file does not exist, flag this as a **critical** failure. + +#### 3b. Frontmatter validation + +Read the file and verify: + +| Field | Expected value | +|-------|---------------| +| `title` | Contains the version string (e.g., `What's new in Aspire 13.2`) | +| `sidebar.label` | `Aspire {VERSION}` (e.g., `Aspire 13.2`) | +| `sidebar.order` | Is `0` (newest release should be first) | + +#### 3c. Content checks + +- The page should contain an **upgrade section** (heading containing "Upgrade") with instructions for upgrading to this version. +- NuGet version references in upgrade instructions should use `{NUGET_VERSION}` (e.g., `13.2.0`). +- The page should mention the corresponding .NET SDK requirement if the major version changed. + +#### 3d. Browser verification (Playwright) + +Using the **playwright-cli** skill, navigate to the preview site's what's-new page and verify: + +```bash +playwright-cli open http://localhost:4321/whats-new/{VERSION_SLUG}/ +playwright-cli snapshot +``` + +- Confirm the page renders without errors. +- Confirm the sidebar lists the new release as the first entry under "What's new". + +#### 3e. Previous release sidebar order + +If a previous what's-new entry existed (e.g., `aspire-13-1.mdx` when verifying `13.2`), verify its `sidebar.order` has been incremented so the new release appears first. + +### Phase 4 — Version references audit + +Scan the documentation for version strings that should have been updated for this release. This catches stale references that still point to a prior version. + +#### 4a. Identify the prior version + +Determine the immediately prior version. For `13.2` the prior is `13.1`; for `13.0` the prior is `9.5` (or whatever the last release of the previous major is). Use the existing what's-new files to determine this. + +#### 4b. Scan for stale version references + +Search the docs content tree for references to the prior NuGet version that appear **outside** of intentional historical context (e.g., upgrade-from examples that deliberately show the old version). + +```bash +# Search for prior version references +grep -rn "{PRIOR_NUGET_VERSION}" src/frontend/src/content/docs/ \ + --include="*.mdx" \ + --exclude-dir="whats-new" +``` + +Also search for stale SDK version references: + +```bash +grep -rn 'Aspire.AppHost.Sdk.*Version="{PRIOR_NUGET_VERSION}"' src/frontend/src/content/docs/ \ + --include="*.mdx" +``` + +#### 4c. Evaluate each match + +For every match found: + +1. **Read the surrounding context** (at least 10 lines before and after). +2. **Classify the reference**: + - **Intentional (old-version example)**: The reference is inside a "before" / upgrade-from code block that deliberately shows the old version to contrast with the new version. These are acceptable — do **not** flag them. + - **Stale (should be updated)**: The reference is in current guidance, installation instructions, or sample code that a user would copy today. Flag these for update. +3. Log each stale reference with file path, line number, and surrounding context. + +#### 4d. Verify new version references + +Spot-check that key documentation pages reference the release version: + +| Page | What to check | +|------|---------------| +| `get-started/install-cli` or equivalent | CLI install commands reference the current release | +| `get-started/first-app` or equivalent | Sample project uses current SDK version | +| `whats-new/upgrade-aspire.mdx` | Upgrade matrix includes the new version | + +### Phase 5 — Integration docs sync + +Run the **update-integrations** skill to ensure integration documentation links are current. + +1. Run the update script: + + ```bash + cd src/frontend && node scripts/update-integrations.js + ``` + +2. Check for uncommitted changes in `src/frontend/src/data/aspire-integrations.json` and `src/frontend/src/data/integration-docs.json`. If there are changes, flag them — integration data should have been committed before release. + +3. Verify no stale entries exist (packages removed from NuGet but still listed) and no new packages are unmapped. + +### Phase 6 — Site-wide smoke test (Playwright) + +Using the **playwright-cli** skill, perform a quick smoke test of the preview site. + +```bash +playwright-cli open http://localhost:4321 +``` + +#### 6a. Landing page + +- Navigate to the root URL. +- Take a snapshot and confirm the page renders. +- Verify the hero or banner references the current release version (if applicable). + +#### 6b. Navigation spot-checks + +Navigate to each top-level section and confirm pages load: + +| Path | Check | +|------|-------| +| `/get-started/` | Page renders, links work | +| `/fundamentals/` | Page renders | +| `/integrations/` | Integration gallery loads | +| `/whats-new/` | Lists current release first | +| `/deployment/` | Page renders | +| `/reference/` | Page renders | + +#### 6c. What's-new page rendering + +Navigate to `/whats-new/{VERSION_SLUG}/` and: + +- Confirm all headings render correctly (snapshot). +- Confirm code blocks are syntax-highlighted. +- Confirm images load (no broken image placeholders). +- Click at least two internal links and verify they resolve. + +### Phase 7 — Cleanup + +1. Stop the preview server (kill the background process). +2. Close any Playwright browser sessions: + + ```bash + playwright-cli close + ``` + +3. Stop any hex1b terminal sessions. + +--- + +## Report format + +After all phases are complete, produce a structured report: + +```markdown +# Release Verification Report + +**Branch:** release/{VERSION} +**Date:** {ISO date} +**Agent:** release-verifier + +## Summary + +| Phase | Status | Details | +|-------|--------|---------| +| 0 — Environment setup | ✅ / ❌ | ... | +| 1 — Clean build | ✅ / ❌ | ... | +| 2 — Preview server | ✅ / ❌ | ... | +| 3 — What's-new entry | ✅ / ❌ | ... | +| 4 — Version references | ✅ / ⚠️ / ❌ | ... | +| 5 — Integration docs | ✅ / ⚠️ / ❌ | ... | +| 6 — Smoke test | ✅ / ❌ | ... | +| 7 — Cleanup | ✅ / ❌ | ... | + +## Critical issues + +[Issues that must be fixed before release] + +### Issue N: [Title] + +**Phase:** N +**Severity:** Critical / High / Medium +**File:** [path with line number] +**Description:** ... +**Recommended fix:** ... + +## Warnings + +[Issues that should be reviewed but may be acceptable] + +## Stale version references + +| File | Line | Context | Classification | +|------|------|---------|---------------| +| ... | ... | ... | Stale / Intentional | + +## Integration docs status + +- Packages in catalog: N +- Mapped entries: N +- New mappings needed: [list] +- Stale mappings removed: [list] +- Unmapped packages: [list] + +## Passed checks + +[Brief list of everything that passed] +``` + +--- + +## Failure handling + +- **Build failure (Phase 1)**: This is a blocking failure. Log the error and continue with remaining phases to gather as much information as possible, but mark the overall verification as **FAILED**. +- **Missing what's-new file (Phase 3a)**: Critical failure. Document it and continue. +- **Stale version references (Phase 4)**: Flag each one with its classification. This is a **warning** unless the stale reference appears in user-facing installation or getting-started instructions, in which case it is **critical**. +- **Integration docs out of sync (Phase 5)**: Warning unless packages are completely unmapped. +- **Smoke test failures (Phase 6)**: Critical if pages fail to render; warning if only cosmetic issues. + +## Skills reference + +This agent depends on the following skills. Read the full skill instructions before using them: + +| Skill | File | When used | +|-------|------|-----------| +| doc-tester | `.github/skills/doc-tester/SKILL.md` | Phase 3 (content validation), Phase 6 (smoke test) | +| hex1b | `.github/skills/hex1b/SKILL.md` | Phase 2 (preview server management), terminal capture | +| playwright-cli | `.github/skills/playwright-cli/SKILL.md` | Phase 3d, Phase 6 (browser-based verification) | +| update-integrations | `.github/skills/update-integrations/SKILL.md` | Phase 5 (integration docs sync) | diff --git a/.github/astro.instructions.md b/.github/astro.instructions.md index 3d5f64646..da81a3874 100644 --- a/.github/astro.instructions.md +++ b/.github/astro.instructions.md @@ -1,214 +1,285 @@ --- -description: 'Astro development standards and best practices for content-driven websites' +description: 'Astro Starlight development standards for aspire.dev documentation site' applyTo: '**/*.astro, **/*.ts, **/*.js, **/*.md, **/*.mdx' --- -# Astro Development Instructions - -Instructions for building high-quality Astro applications following the content-driven, server-first architecture with modern best practices. - -## Project Context -- Astro 5.x with Islands Architecture and Content Layer API -- TypeScript for type safety and better DX with auto-generated types -- Content-driven websites (blogs, marketing, e-commerce, documentation) -- Server-first rendering with selective client-side hydration -- Support for multiple UI frameworks (React, Vue, Svelte, Solid, etc.) -- Static site generation (SSG) by default with optional server-side rendering (SSR) -- Enhanced performance with modern content loading and build optimizations - -## Development Standards - -### Architecture -- Embrace the Islands Architecture: server-render by default, hydrate selectively -- Organize content with Content Collections for type-safe Markdown/MDX management -- Structure projects by feature or content type for scalability -- Use component-based architecture with clear separation of concerns -- Implement progressive enhancement patterns -- Follow Multi-Page App (MPA) approach over Single-Page App (SPA) patterns - -### TypeScript Integration -- Configure `tsconfig.json` with recommended v5.0 settings: -```json -{ - "extends": "astro/tsconfigs/base", - "include": [".astro/types.d.ts", "**/*"], - "exclude": ["dist"] -} +# aspire.dev Development Instructions + +This is the aspire.dev documentation site, built with [Astro Starlight](https://starlight.astro.build/). All source lives under `src/frontend/`. + +## Project Stack + +- **Astro 5.x** with **Starlight** documentation theme +- **TypeScript** (strict mode, `astro/tsconfigs/strict`) +- **Static site generation** (SSG) — zero client-side JS by default +- **pnpm** as the package manager (`pnpm install`, `pnpm dev`, `pnpm build`) +- **15 locales** with Lunaria translation tracking + +## Running Locally + +```bash +cd src/frontend +pnpm install +pnpm dev # starts dev server at http://localhost:4321 +``` + +Search is disabled in dev mode — use `pnpm build && pnpm preview` to test search. Running `pnpm dev` is sufficient to verify documentation rendering changes; a full `pnpm build` is not required. + +## Project Structure + +``` +src/frontend/ +├── astro.config.mjs # Starlight config, plugins, integrations +├── ec.config.mjs # Expressive Code config (themes, plugins) +├── tsconfig.json # TypeScript config with path aliases +├── config/ # Sidebar topics, locales, redirects, cookies, SEO head +│ └── sidebar/ # Sidebar topic modules (7 files) +├── src/ +│ ├── content.config.ts # Content collections (docs, i18n, packages) +│ ├── route-data-middleware.ts +│ ├── assets/ # Images, icons, logos +│ ├── components/ # Custom Astro components +│ │ └── starlight/ # Starlight component overrides +│ ├── content/docs/ # All documentation pages (MDX/MD) +│ ├── data/ # JSON data files + pkgs/ API reference +│ ├── expressive-code-plugins/ # Custom EC plugins (disable-copy) +│ ├── pages/ # Astro page routes +│ ├── styles/ # Global CSS (site.css) +│ └── utils/ # Helpers, package utils, sample tags +``` + +## Import Aliases + +Always use these path aliases (defined in `tsconfig.json`) instead of relative paths: + +| Alias | Resolves to | +|---|---| +| `@assets/*` | `./src/assets/*` | +| `@components/*` | `./src/components/*` | +| `@data/*` | `./src/data/*` | +| `@utils/*` | `./src/utils/*` | + +Example usage in MDX frontmatter imports: + +```mdx +import LearnMore from '@components/LearnMore.astro'; +import ThemeImage from '@components/ThemeImage.astro'; +import { Aside, Code, Steps, LinkButton, Tabs, TabItem } from '@astrojs/starlight/components'; +``` + +## Starlight Plugins + +The site uses these Starlight plugins (configured in `astro.config.mjs`): + +| Plugin | Purpose | +|---|---| +| `starlight-sidebar-topics` | Dynamic sidebar organized by topic areas | +| `starlight-page-actions` | Share + AI action buttons (Copilot, Claude, ChatGPT) | +| `starlight-image-zoom` | Click-to-zoom images with captions | +| `starlight-kbd` | OS-aware keyboard shortcut display | +| `starlight-github-alerts` | GitHub-style `> [!NOTE]` callout syntax | +| `starlight-links-validator` | Build-time link checking | +| `starlight-scroll-to-top` | Scroll-to-top button | +| `starlight-llms-txt` | AI training data formatting | +| `@lunariajs/starlight` | i18n translation dashboard | +| `@catppuccin/starlight` | Theme integration | +| `astro-mermaid` | Mermaid diagram rendering | + +## Starlight Component Overrides + +Custom overrides live in `src/components/starlight/` and are registered in `astro.config.mjs` under `components:`: + +- `EditLink.astro` — adds translation link +- `Footer.astro` — custom 4-column footer layout +- `Head.astro` — git metadata, auto-language detection, accessibility +- `Header.astro` — custom nav with cookie/CLI buttons +- `Hero.astro` — enhanced hero with image variants +- `MarkdownContent.astro` — image zoom wrapper +- `Search.astro` — search with API docs notice +- `Sidebar.astro` — enhanced sidebar with API filter & collapse +- `SocialIcons.astro` — additional social/misc buttons + +When modifying these, study the corresponding Starlight source component to understand the expected props and slots. + +## Custom Components + +Many reusable components exist in `src/components/`. Before creating a new component, check what already exists. Key categories: + +- **Layout/UI**: `HeroSection`, `TopicHero`, `IconLinkCard`, `MediaCard`, `SimpleCard`, `FluidGrid`, `Pivot`, `Expand` +- **Integrations**: `IntegrationCard`, `IntegrationGrid`, `Integrations`, `IntegrationTotals` +- **Media**: `LoopingImage`, `LoopingVideo`, `VimeoCard`, `YouTubeCard`, `TerminalShowcase` +- **Content helpers**: `Include`, `Placeholder`, `InstallAspireCLI`, `CodespacesButton`, `LearnMore` +- **Interactive**: `OsAwareTabs`, `AppHostBuilder`, `QuickStartJourney`, `TestimonialCarousel` +- **API reference**: `TypeHero`, `TypeSignature`, `MemberCard`, `MemberList`, `EnumTable`, `InheritanceDiagram` + +Always follow existing component patterns: `.astro` files with frontmatter props at top, scoped styles, and PascalCase naming. + +## Content Collections + +Defined in `src/content.config.ts`: + +- **docs** — uses Starlight's docs loader with extended schema fields: `renderBlocking`, `giscus`, `category`, `pageActions` +- **i18n** — Starlight i18n loader for 15 locales +- **packages** — auto-generated API reference JSON from `src/data/pkgs/` + +## Writing Documentation (MDX) + +### Frontmatter + +Every page needs at minimum a `title`. Custom fields include: + +```yaml +--- +title: My page title +category: conceptual # conceptual | quickstart | tutorial | blog | reference | sample +giscus: true # enable comments +pageActions: false # disable AI/share actions +--- ``` -- Types auto-generated in `.astro/types.d.ts` (replaces `src/env.d.ts`) -- Run `astro sync` to generate/update type definitions -- Define component props with TypeScript interfaces -- Leverage auto-generated types for content collections and Content Layer API - -### Component Design -- Use `.astro` components for static, server-rendered content -- Import framework components (React, Vue, Svelte) only when interactivity is needed -- Follow Astro's component script structure: frontmatter at top, template below -- Use meaningful component names following PascalCase convention -- Keep components focused and composable -- Implement proper prop validation and default values - -### Content Collections - -#### Modern Content Layer API (v5.0+) -- Define collections in `src/content.config.ts` using the new Content Layer API -- Use built-in loaders: `glob()` for file-based content, `file()` for single files -- Leverage enhanced performance and scalability with the new loading system -- Example with Content Layer API: -```typescript -import { defineCollection, z } from 'astro:content'; -import { glob } from 'astro/loaders'; - -const blog = defineCollection({ - loader: glob({ pattern: '**/*.md', base: './src/content/blog' }), - schema: z.object({ - title: z.string(), - pubDate: z.date(), - tags: z.array(z.string()).optional() - }) -}); + +### Key Conventions + +- **Heading 1 is reserved** for the page title from frontmatter — start content headings at `##` +- **Use sentence case** for all headings and sidebar labels +- **Use active voice** and clear, concise language +- **Site-relative links** must include a trailing slash: `[First app](/get-started/first-app/)` +- **Unordered lists** use `-` (not `*`) +- **Italic text** uses `_` (not `*`) +- **Code blocks** use triple backticks with language identifier and optional `title`: + ````md + ```csharp title="Program.cs" + var builder = DistributedApplication.CreateBuilder(args); + ``` + ```` + +### Starlight Components in MDX + +Import from `@astrojs/starlight/components`: + +```mdx +import { Aside, Code, Steps, LinkButton, Tabs, TabItem } from '@astrojs/starlight/components'; ``` -#### Legacy Collections (backward compatible) -- Legacy `type: 'content'` collections still supported via automatic glob() implementation -- Migrate existing collections by adding explicit `loader` configuration -- Use type-safe queries with `getCollection()` and `getEntry()` -- Structure content with frontmatter validation and auto-generated types - -### View Transitions & Client-Side Routing -- Enable with `` component in layout head (renamed from `` in v5.0) -- Import from `astro:transitions`: `import { ClientRouter } from 'astro:transitions'` -- Provides SPA-like navigation without full page reloads -- Customize transition animations with CSS and view-transition-name -- Maintain state across page navigations with persistent islands -- Use `transition:persist` directive to preserve component state - -### Performance Optimization -- Default to zero JavaScript - only add interactivity where needed -- Use client directives strategically (`client:load`, `client:idle`, `client:visible`) -- Implement lazy loading for images and components -- Optimize static assets with Astro's built-in optimization -- Leverage Content Layer API for faster content loading and builds -- Minimize bundle size by avoiding unnecessary client-side JavaScript - -### Styling -- Use scoped styles in `.astro` components by default -- Implement CSS preprocessing (Sass, Less) when needed -- Use CSS custom properties for theming and design systems -- Follow mobile-first responsive design principles -- Ensure accessibility with semantic HTML and proper ARIA attributes -- Consider utility-first frameworks (Tailwind CSS) for rapid development - -### Client-Side Interactivity -- Use framework components (React, Vue, Svelte) for interactive elements -- Choose the right hydration strategy based on user interaction patterns -- Implement state management within framework boundaries -- Handle client-side routing carefully to maintain MPA benefits -- Use Web Components for framework-agnostic interactivity -- Share state between islands using stores or custom events - -### API Routes and SSR -- Create API routes in `src/pages/api/` for dynamic functionality -- Use proper HTTP methods and status codes -- Implement request validation and error handling -- Enable SSR mode for dynamic content requirements -- Use middleware for authentication and request processing -- Handle environment variables securely - -### SEO and Meta Management -- Use Astro's built-in SEO components and meta tag management -- Implement proper Open Graph and Twitter Card metadata -- Generate sitemaps automatically for better search indexing -- Use semantic HTML structure for better accessibility and SEO -- Implement structured data (JSON-LD) for rich snippets -- Optimize page titles and descriptions for search engines - -### Inclusive and Accessible Content - -#### Writing with Inclusivity -- **Use inclusive language**: Respect all readers regardless of ability, background, identity, or experience level -- **People-first language**: Say "person who uses a screen reader" not "blind user" -- **Avoid assumptions**: Don't use phrases like "as you can see" or "simply click" -- **No ableist language**: Avoid terms like "blind to," "crippled by," "crazy," "insane," "lame" -- **Gender-neutral language**: Use "they/them" or rewrite to avoid gendered pronouns -- **Global perspective**: Avoid idioms, colloquialisms, and culturally-specific references - -#### Plain Language Principles -- **Write short sentences**: Aim for 15-20 words conveying one main idea -- **Use common words**: Avoid jargon or define technical terms on first use -- **Active voice**: Prefer "The system processes" over "is processed by" -- **Break up text**: Keep paragraphs to 3-5 sentences -- **Descriptive headings**: Make section purposes clear for scanning - -#### Accessible Content Structure -- **Proper heading hierarchy**: Use H1 → H2 → H3 without skipping levels -- **One H1 per page**: Establish clear document hierarchy -- **Meaningful link text**: Use "Read the deployment guide" not "Click here" -- **Alt text for images**: Describe informative images, use `alt=""` for decorative ones -- **Lists for structure**: Use bulleted/numbered lists to break up dense text -- **Table headers**: Always include `` elements for column and row headers - -#### Global and Cultural Considerations -- **Universal dates**: Write "January 15, 2025" not "1/15/25" -- **Time zones**: Specify zones when referencing specific times -- **Measurements**: Use metric alongside imperial when relevant -- **Diverse examples**: Use varied names and scenarios reflecting global audiences -- **Avoid stereotypes**: Represent different contexts and industries in examples - -### Image Optimization -- Use Astro's `` component for automatic optimization -- Implement responsive images with proper srcset generation -- Use WebP and AVIF formats for modern browsers -- Lazy load images below the fold -- Provide proper alt text for accessibility -- Optimize images at build time for better performance - -### Data Fetching -- Fetch data at build time in component frontmatter -- Use dynamic imports for conditional data loading -- Implement proper error handling for external API calls -- Cache expensive operations during build process -- Use Astro's built-in fetch with automatic TypeScript inference -- Handle loading states and fallbacks appropriately - -### Build & Deployment -- Optimize static assets with Astro's built-in optimizations -- Configure deployment for static (SSG) or hybrid (SSR) rendering -- Use environment variables for configuration management -- Enable compression and caching for production builds - -## Key Astro v5.0 Updates - -### Breaking Changes -- **ClientRouter**: Use `` instead of `` -- **TypeScript**: Auto-generated types in `.astro/types.d.ts` (run `astro sync`) -- **Content Layer API**: New `glob()` and `file()` loaders for enhanced performance - -### Migration Example -```typescript -// Modern Content Layer API -import { defineCollection, z } from 'astro:content'; -import { glob } from 'astro/loaders'; - -const blog = defineCollection({ - loader: glob({ pattern: '**/*.md', base: './src/content/blog' }), - schema: z.object({ title: z.string(), pubDate: z.date() }) -}); +- **` +## Security + +The Aspire MCP server is a development-time tool designed for local use. Understanding its security model helps teams evaluate it for enterprise environments. + +### Security model overview + +The Aspire MCP server uses the **STDIO transport protocol** when started via `aspire agent mcp`. In this mode: + +- The MCP server runs as a **local child process** spawned by your AI assistant. +- Communication happens over **standard input/output (STDIO) pipes** between the AI assistant and the MCP server process. +- There are **no open network ports** — the MCP server doesn't listen on any network interface. +- Only the parent process (your AI assistant) can communicate with the MCP server. + + + +### What data is accessible + +The MCP server provides AI assistants with access to the following data from your running AppHost: + +- **Resource metadata** — resource names, types, states, health status, endpoints, and available commands. +- **Console logs** — standard output and error streams from resources. +- **Structured logs** — structured log entries from resources via OpenTelemetry. +- **Distributed traces** — trace data showing request flow across resources. +- **Integration catalog** — the list of available Aspire hosting integration packages and their documentation. + +The MCP server does **not** expose: + +- Source code or file system contents. +- Environment variable values or secrets stored in configuration. +- Network traffic or raw request/response payloads. +- Access to the host machine beyond the Aspire AppHost process. + +You can further restrict what the MCP server exposes by using `ExcludeFromMcp()` on specific resources, as described in the [Tools](#tools) section. + +### Authentication + +When using the STDIO transport (the default with `aspire agent mcp`), no additional authentication is required because communication is restricted to the local process pipe. + +For the HTTP-based MCP endpoint exposed by the Aspire dashboard (used in [manual MCP configuration](/dashboard/mcp-server/) for older Aspire versions), an API key (`x-mcp-api-key` header) is required to authenticate requests. This key is generated automatically when the AppHost starts. + +### Enterprise deployment considerations + +For teams evaluating the Aspire MCP server for organizational use: + +- **Development-time only** — the MCP server is a development tool and is not included in published or deployed applications. It runs only during local development with `aspire run`. +- **No external network access** — using STDIO transport, the server has no network listeners and cannot be reached from other machines. +- **Data stays local** — telemetry and resource data remain on the developer's machine. The MCP server doesn't transmit data to external services. Data shared with AI assistants is governed by the AI assistant's own data policies. +- **Granular access control** — use `ExcludeFromMcp()` to prevent sensitive resources and their associated telemetry from being accessible to AI assistants. +- **No persistent storage** — the MCP server doesn't write data to disk. All data is held in memory for the duration of the development session. +- **Open specification** — the MCP server implements the open [Model Context Protocol specification](https://modelcontextprotocol.io/), allowing security teams to review the protocol. + ## Troubleshooting Aspire MCP is designed to work seamlessly with AI assistants, but you may encounter some setup challenges depending on your environment. If you run into issues, check the [open MCP issues on GitHub](https://github.com/dotnet/aspire/issues?q=is%3Aissue+is%3Aopen+label%3Aarea-mcp) for known problems and solutions. +### AppHost detection and lifecycle + +The Aspire MCP server automatically detects running AppHosts within the working directory scope. Understanding this lifecycle helps troubleshoot connection issues: + +- When the MCP server starts (via `aspire agent mcp`), it scans for running AppHost processes. +- The MCP server **continuously monitors** for AppHost changes — you don't need to restart the MCP server when starting or stopping AppHosts. +- Use `list_apphosts` to see which AppHosts are currently detected. +- Use `select_apphost` to switch between multiple running AppHosts. + + + +### Claude Code integration issues + +If you experience issues with Claude Code and the Aspire MCP server: + +- **Verify configuration** — ensure `.mcp.json` exists in your project root with the correct configuration. Run `aspire agent init` to regenerate it if needed. +- **Windows `cmd.exe` prefix** — on Windows, commands like `npx` require a `cmd.exe /c` prefix. See [GitHub issue #14000](https://github.com/anthropics/claude-code/issues/14000) for details. +- **Restart Claude Code** — if the MCP server connection appears stale, restart Claude Code to re-establish the STDIO connection. +- **Check Claude Code MCP logs** — use Claude Code's built-in MCP debugging to inspect connection status. Refer to the [Claude Code MCP documentation](https://docs.claude.com/en/docs/claude-code/mcp) for details. + +### Debugging MCP connection problems + +If your AI assistant can't connect to the Aspire MCP server: + + + +1. Verify the Aspire CLI is installed and available on your `PATH`: + + ```bash title="Aspire CLI" + aspire --version + ``` + +1. Confirm your AppHost is running: + + ```bash title="Aspire CLI" + aspire run + ``` + +1. Test the MCP server directly by running it manually: + + ```bash title="Aspire CLI" + aspire agent mcp + ``` + + If the server starts without errors, the issue is likely in your AI assistant's configuration. + +1. Regenerate configuration files: + + ```bash title="Aspire CLI" + aspire agent init + ``` + +1. Verify the generated configuration file matches your AI assistant's expected format (see [Understanding the configuration](#understanding-the-configuration)). + + + +## Deployment considerations + +The Aspire MCP server is a development-time tool and should not be included in published or deployed applications. If your AppHost includes dev-only resources (such as MCP tooling or other development utilities), you may need to conditionally exclude them during deployment. + +### Exclude dev-only resources from publish + +Use `ExecutionContext.IsRunMode` to conditionally add resources that should only be available during local development: + +```csharp title="C# — AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); + +var api = builder.AddProject("api"); + +if (builder.ExecutionContext.IsRunMode) +{ + // Resources added here are only available during + // local development with 'aspire run', and are + // excluded from 'aspire deploy' and 'aspire publish'. + builder.AddContainer("dev-tool", "some-dev-image"); +} + +builder.Build().Run(); +``` + + + ## Limitations Aspire MCP is a powerful tool, but there are a few things to keep in mind when using it. @@ -272,7 +411,8 @@ AI models have limits on how much data they can process at once. Aspire MCP may ## See also -- [aspire mcp command](/reference/cli/commands/aspire-mcp/) -- [aspire mcp init command](/reference/cli/commands/aspire-mcp-init/) -- [aspire mcp start command](/reference/cli/commands/aspire-mcp-start/) +- [aspire agent command](/reference/cli/commands/aspire-agent/) +- [aspire agent init command](/reference/cli/commands/aspire-agent-init/) +- [aspire agent mcp command](/reference/cli/commands/aspire-agent-mcp/) +- [Dashboard security considerations](/dashboard/security-considerations/) - [GitHub Copilot in the Dashboard](/dashboard/copilot/) diff --git a/src/frontend/src/content/docs/get-started/deploy-first-app.mdx b/src/frontend/src/content/docs/get-started/deploy-first-app.mdx index 752f092c0..0be45da3c 100644 --- a/src/frontend/src/content/docs/get-started/deploy-first-app.mdx +++ b/src/frontend/src/content/docs/get-started/deploy-first-app.mdx @@ -1,7 +1,6 @@ --- title: Deploy your first Aspire app description: Learn how to deploy your first Aspire application to the cloud. -next: false --- import { Image } from 'astro:assets'; @@ -23,7 +22,7 @@ import dockerIcon from '@assets/icons/docker.svg'; options={[ { id: "csharp", title: "C#" }, { id: "python", title: "Python" }, - { id: "javascript", title: "JavaScript (coming soon)", disabled: true }, + { id: "javascript", title: "JavaScript" }, ]} /> @@ -73,6 +72,22 @@ architecture-beta The React (Vite) & FastAPI starter template consists of two resources that are deployed as a single container. The FastAPI server hosts both the API and the static frontend files generated by React. + + +```mermaid +architecture-beta + group docker(logos:docker-icon)[NodeJS and static site server container] + + service api(logos:nodejs-icon)[API service] in docker + service http(iconoir:server-connection)[https] in docker + service frontend(logos:react)[React front end] in docker + + frontend:L --> R:http + http:L --> R:api +``` + +The React (Vite) & Express starter template consists of two resources that are deployed as a single container. The Express server hosts both the API and the static frontend files generated by React. + ## Prerequisites @@ -185,6 +200,30 @@ In the AppHost, chain a call to the appropriate environment API method to config builder.Build().Run(); ``` + + ```typescript title="TypeScript — apphost.ts" {5-6} + import { createBuilder } from './.modules/aspire.js'; + + const builder = await createBuilder(); + + // Add the following line to configure the Docker Compose environment + await builder.addDockerComposeEnvironment("env"); + + const app = await builder + .addNodeApp("app", "./api", "src/index.ts") + .withHttpEndpoint({ env: "PORT" }) + .withExternalHttpEndpoints(); + + const frontend = await builder + .addViteApp("frontend", "./frontend") + .withReference(app) + .waitFor(app); + + await app.publishWithContainerFiles(frontend, "./static"); + + await builder.build().run(); + ``` + - `AddDockerComposeEnvironment` — Configures the Docker Compose environment for deployment. This call implicitly adds support for containerizing resources in the AppHost as part of deployment. - `WithExternalHttpEndpoints` — Exposes HTTP endpoints for the resource when deployed. @@ -237,6 +276,30 @@ In the AppHost, chain a call to the appropriate environment API method to config builder.Build().Run(); ``` + + ```typescript title="TypeScript — apphost.ts" {5-6} + import { createBuilder } from './.modules/aspire.js'; + + const builder = await createBuilder(); + + // Add the following line to configure the Azure App Container environment + await builder.addAzureContainerAppEnvironment("env"); + + const app = await builder + .addNodeApp("app", "./api", "src/index.ts") + .withHttpEndpoint({ env: "PORT" }) + .withExternalHttpEndpoints(); + + const frontend = await builder + .addViteApp("frontend", "./frontend") + .withReference(app) + .waitFor(app); + + await app.publishWithContainerFiles(frontend, "./static"); + + await builder.build().run(); + ``` + - `AddAzureContainerAppEnvironment` — Configures the Azure App Container environment for deployment. This call implicitly adds support for containerizing resources in the AppHost as part of deployment. - `WithExternalHttpEndpoints` — Exposes HTTP endpoints for the resource when deployed. @@ -409,6 +472,80 @@ Now that you've added the deployment package and updated your AppHost, you can d + + + + + + ```bash title="Aspire CLI - Deploy Express/React app with Docker Compose" + 13:23:29 (pipeline execution) → Starting pipeline execution... + 13:23:29 (publish-env) → Starting publish-env... + 13:23:29 (build-prereq) → Starting build-prereq... + 13:23:29 (deploy-prereq) → Starting deploy-prereq... + 13:23:29 (build-prereq) ✓ build-prereq completed successfully + 13:23:29 (deploy-prereq) i [INF] Initializing deployment for environment 'Production' + 13:23:29 (publish-env) i [INF] Generating Compose output + 13:23:29 (deploy-prereq) i [INF] Setting default deploy tag 'aspire-deploy-20251107192329' for compute resource(s). + 13:23:29 (deploy-prereq) ✓ deploy-prereq completed successfully + 13:23:29 (build-frontend) → Starting build-frontend... + 13:23:29 (build-frontend) i [INF] Building container image for resource frontend + 13:23:29 (build-frontend) i [INF] Building image: frontend + 13:23:29 (publish-env) → Writing the Docker Compose file to the output path. + 13:23:29 (publish-env) ✓ Docker Compose file written successfully to ./aspire-app/aspire-output/docker-compose.yaml. (0.0s) + 13:23:29 (publish-env) ✓ publish-env completed successfully + 13:23:29 (publish) → Starting publish... + 13:23:29 (publish) ✓ publish completed successfully + 13:23:51 (build-frontend) i [INF] docker buildx for frontend succeeded. + 13:23:51 (build-frontend) i [INF] Building image for frontend completed + 13:23:51 (build-frontend) ✓ build-frontend completed successfully + 13:23:51 (build-app) → Starting build-app... + 13:23:51 (build-app) i [INF] Building container image for resource app + 13:23:51 (build-app) i [INF] Building image: app + 13:24:07 (build-app) i [INF] docker buildx for app succeeded. + 13:24:07 (build-app) i [INF] Building image for app completed + 13:24:07 (build-app) ✓ build-app completed successfully + 13:24:07 (build) → Starting build... + 13:24:07 (build) ✓ build completed successfully + 13:24:07 (prepare-env) → Starting prepare-env... + 13:24:07 (prepare-env) ✓ prepare-env completed successfully + 13:24:07 (docker-compose-up-env) → Starting docker-compose-up-env... + 13:24:07 (docker-compose-up-env) → Running docker compose up for env + 13:24:13 (docker-compose-up-env) ✓ Service env is now running with Docker Compose locally (5.6s) + 13:24:13 (docker-compose-up-env) ✓ docker-compose-up-env completed successfully + 13:24:13 (print-env-dashboard-summary) → Starting print-env-dashboard-summary... + 13:24:13 (print-app-summary) → Starting print-app-summary... + 13:24:13 (print-env-dashboard-summary) i [INF] Successfully deployed env-dashboard to http://localhost:54633. + 13:24:13 (print-app-summary) i [INF] Successfully deployed app to http://localhost:54463. + 13:24:13 (print-env-dashboard-summary) ✓ print-env-dashboard-summary completed successfully + 13:24:13 (print-app-summary) ✓ print-app-summary completed successfully + 13:24:13 (deploy) → Starting deploy... + 13:24:13 (deploy) ✓ deploy completed successfully + 13:24:13 (pipeline execution) ✓ Completed successfully + ------------------------------------------------------------ + ✓ 13/13 steps succeeded • Total time: 44.1s + + Steps Summary: + 44.0 s ✓ pipeline execution + 22.2 s ✓ build-frontend + 16.3 s ✓ build-app + 5.6 s ✓ docker-compose-up-env + 0.0 s ✓ publish-env + 0.0 s ✓ deploy-prereq + 0.0 s ✓ build-prereq + 0.0 s ✓ print-env-dashboard-summary + 0.0 s ✓ print-app-summary + 0.0 s ✓ deploy + 0.0 s ✓ build + 0.0 s ✓ prepare-env + 0.0 s ✓ publish + + ✓ PIPELINE SUCCEEDED + ------------------------------------------------------------ + ``` + + + @@ -632,6 +769,88 @@ Now that you've added the deployment package and updated your AppHost, you can d + + + + + + ```bash title="Aspire CLI - Deploy Express/React app to Azure App Containers" + 09:24:18 (pipeline execution) → Starting pipeline execution... + 09:24:18 (deploy-prereq) → Starting deploy-prereq... + 09:24:18 (build-prereq) → Starting build-prereq... + 09:24:18 (deploy-prereq) i [INF] Initializing deployment for environment 'Production' + 09:24:18 (build-prereq) ✓ build-prereq completed successfully + 09:24:18 (deploy-prereq) i [INF] Setting default deploy tag 'aspire-deploy-20251110152418' for compute resource(s). + 09:24:18 (deploy-prereq) ✓ deploy-prereq completed successfully + 09:24:18 (validate-azure-login) → Starting validate-azure-login... + 09:24:18 (build-frontend) → Starting build-frontend... + 09:24:18 (build-frontend) i [INF] Building container image for resource frontend + 09:24:18 (build-frontend) i [INF] Building image: frontend + 09:24:19 (validate-azure-login) ✓ Azure CLI authentication validated successfully + 09:24:19 (create-provisioning-context) → Starting create-provisioning-context... + 09:24:19 (create-provisioning-context) i [INF] Using DefaultAzureCredential for provisioning. + 09:24:22 (create-provisioning-context) ✓ create-provisioning-context completed successfully + 09:24:22 (provision-env) → Starting provision-env... + 09:24:22 (provision-env) → Deploying env + 09:24:22 (provision-env) ✓ Using existing deployment for env (0.0s) + 09:24:22 (provision-env) ✓ provision-env completed successfully + 09:24:22 (login-to-acr-env) → Starting login-to-acr-env... + 09:24:22 (build-frontend) i [INF] docker buildx for frontend succeeded. + 09:24:22 (build-frontend) i [INF] Building image for frontend completed + 09:24:22 (build-frontend) ✓ build-frontend completed successfully + 09:24:22 (build-app) → Starting build-app... + 09:24:22 (build-app) i [INF] Building container image for resource app + 09:24:22 (build-app) i [INF] Building image: app + 09:24:25 (login-to-acr-env) ✓ Successfully logged in to ACR (3.2s) + 09:24:25 (login-to-acr-env) ✓ login-to-acr-env completed successfully + 09:24:27 (build-app) i [INF] docker buildx for app succeeded. + 09:24:27 (build-app) i [INF] Building image for app completed + 09:24:27 (build-app) ✓ build-app completed successfully + 09:24:27 (push-app) → Starting push-app... + 09:24:27 (push-app) → Pushing app to ACR + 09:25:06 (push-app) ✓ Successfully pushed app to ACR (38.5s) + 09:25:06 (push-app) ✓ push-app completed successfully + 09:25:06 (provision-app-containerapp) → Starting provision-app-containerapp... + 09:25:06 (provision-app-containerapp) → Deploying app-containerapp + 09:25:29 (provision-app-containerapp) ✓ Successfully provisioned app-containerapp (23.6s) + 09:25:29 (provision-app-containerapp) ✓ provision-app-containerapp completed successfully + 09:25:29 (print-app-summary) → Starting print-app-summary... + 09:25:29 (provision-azure-bicep-resources) → Starting provision-azure-bicep-resources... + 09:25:29 (provision-azure-bicep-resources) ✓ provision-azure-bicep-resources completed successfully + 09:25:29 (print-dashboard-url-env) → Starting print-dashboard-url-env... + 09:25:29 (print-app-summary) i [INF] Successfully deployed app to {DEPLOY_URL} + 09:25:29 (print-app-summary) ✓ print-app-summary completed successfully + 09:25:29 (print-dashboard-url-env) ✓ Dashboard available at dashboard URL + 09:25:29 (deploy) → Starting deploy... + 09:25:29 (deploy) ✓ deploy completed successfully + 09:25:29 (pipeline execution) ✓ Completed successfully + ------------------------------------------------------------ + ✓ 15/15 steps succeeded • Total time: 71.6s + + Steps Summary: + 71.5 s ✓ pipeline execution + 38.5 s ✓ push-app + 23.6 s ✓ provision-app-containerapp + 4.8 s ✓ build-frontend + 4.7 s ✓ build-app + 3.2 s ✓ login-to-acr-env + 3.1 s ✓ create-provisioning-context + 1.3 s ✓ validate-azure-login + 0.0 s ✓ provision-env + 0.0 s ✓ deploy-prereq + 0.0 s ✓ print-app-summary + 0.0 s ✓ build-prereq + 0.0 s ✓ print-dashboard-url-env + 0.0 s ✓ provision-azure-bicep-resources + 0.0 s ✓ deploy + + ✓ PIPELINE SUCCEEDED + ------------------------------------------------------------ + ``` + + + @@ -862,6 +1081,72 @@ After a deployment, the Aspire CLI writes to the provided output path (or the de driver: "bridge" ``` + + + + - aspire-output + - .env + - .env.Production + - app.Dockerfile + - docker-compose.yaml + + + The `aspire-output` directory contains the generated environment variables, an `app.Dockerfile`, and the Docker Compose configuration. The best part is, these files are opaque to you as a developer—you don't need to write them yourself! + + The `app.Dockerfile` is generated as a multi-stage Dockerfile to build the Express API and also serve the React front end: + + ```dockerfile title="./aspire-output/app.Dockerfile" + ARG FRONTEND_IMAGENAME=frontend:latest + + FROM node:22-slim AS builder + + WORKDIR /app + + COPY package*.json ./ + RUN npm ci --production + + COPY . . + + FROM ${FRONTEND_IMAGENAME} AS frontend_stage + + FROM node:22-slim AS app + + COPY --from=frontend_stage /app/dist /app/./static + COPY --from=builder /app /app + + USER node + WORKDIR /app + ENTRYPOINT ["node", "--import", "tsx", "src/index.ts"] + ``` + + Finally, the `docker-compose.yaml` file defines the service: + + ```yaml title="./aspire-output/docker-compose.yaml" + services: + env-dashboard: + image: "mcr.microsoft.com/dotnet/nightly/aspire-dashboard:latest" + expose: + - "18888" + - "18889" + networks: + - "aspire" + restart: "always" + app: + image: "${APP_IMAGE}" + environment: + PORT: "8000" + OTEL_EXPORTER_OTLP_ENDPOINT: "http://env-dashboard:18889" + OTEL_EXPORTER_OTLP_PROTOCOL: "grpc" + OTEL_SERVICE_NAME: "app" + ports: + - "8000" + networks: + - "aspire" + networks: + aspire: + driver: "bridge" + ``` + @@ -881,6 +1166,12 @@ After a deployment, the Aspire CLI writes to the provided output path (or the de - .aspire/deployments/[AppHost-Sha256]/production.json + + + - %USERPROFILE% + - .aspire/deployments/[AppHost-Sha256]/production.json + +