astro-expert — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited astro-expert (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Expert knowledge for building production-ready frontends with Astro — combining static rendering, selective hydration, and React islands for interactive components.
client:load — hydrate immediately (forms, critical interactivity)client:idle — hydrate when browser is idle (non-critical widgets)client:visible — hydrate when in viewport (below-the-fold islands)client:only="react" — skip SSR entirely for fully client-driven components (SSE consumers, real-time UIs)src/
├── layouts/ # Astro layout shells (zero JS)
├── pages/ # File-based routing (.astro files)
│ └── [id].astro # Dynamic segments
├── components/
│ ├── layout/ # Pure Astro layout primitives
│ ├── ui/ # Shared React primitives (Button, Card, Badge)
│ └── features/ # React islands — business-logic components
├── lib/ # Utilities, API client, hooks
│ ├── utils.ts # cn() helper, formatters
│ ├── api.ts # Backend API client
│ └── useEventStream.ts # SSE hook
├── styles/
│ ├── tokens.css # CSS custom properties (color, spacing, radius)
│ └── app.css # Tailwind entry + base overrides
└── types/ # Shared TypeScript interfaces// astro.config.mjs
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
import tailwind from '@astrojs/tailwind';
export default defineConfig({
integrations: [
react(),
tailwind({ applyBaseStyles: false }),
],
output: 'hybrid', // static by default, opt-in SSR per page
});Mark dynamic pages: export const prerender = false;
---
// pages/projects/[id].astro — static shell
import BaseLayout from '@/layouts/BaseLayout.astro';
import PipelineStream from '@/components/features/PipelineStream';
const { id } = Astro.params;
---
<BaseLayout title="Project">
<!-- client:only skips SSR — needed for SSE hooks -->
<PipelineStream projectId={id} client:only="react" />
</BaseLayout>// lib/useEventStream.ts
import { useEffect, useReducer } from 'react';
type PipelineEvent = {
type: 'brief_normalised' | 'scripts_generated' | 'content_delivered';
payload: Record<string, unknown>;
timestamp: string;
};
export function useEventStream(projectId: string) {
const [events, dispatch] = useReducer(
(state: PipelineEvent[], action: PipelineEvent) => [...state, action],
[]
);
useEffect(() => {
const es = new EventSource(`/api/v1/projects/${projectId}/stream`);
es.onmessage = (e) => dispatch(JSON.parse(e.data));
return () => es.close();
}, [projectId]);
return events;
}client:load — user expects immediate interactionclient:visible — only hydrate when scrolled into viewclient:only="react" — no SSR for event-driven state<Image /> component from astro:assetsfont-display: swap + preload critical fonts in <head>client:* directiveuseReducedMotion respected in all animated islandsfocus-visible states present on all interactive controlses.close() in cleanup)astro check)| Layer | Tool |
|---|---|
| Framework | Astro 4.x (hybrid output) |
| UI components | React 18 islands |
| Styling | Tailwind CSS v3 + CSS variables |
| Primitives | shadcn/ui pattern (composable, token-driven) |
| Animation | Framer Motion (selective, reduced-motion aware) |
| Icons | lucide-react |
| Type safety | TypeScript strict mode |
| Real-time | EventSource (SSE) via useEventStream hook |
_Last reviewed: 2026-05-14 — polish per #24._
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.