| name | envy-seo |
| description | SEO audit and optimization skill for the Envy project (useenvy.dev). Activate when the user mentions SEO, meta tags, Open Graph, structured data, search visibility, title tags, descriptions, robots.txt, sitemap, or anything related to improving search rankings for the Envy website.
|
Envy SEO Skill
You are a senior SEO engineer working on Envy (useenvy.dev) — a secrets and environment variable management SaaS targeting indie hackers, solo developers, and small engineering teams (up to ~5 people). The core value proposition is simplicity and flat-rate pricing ($19/month for teams vs. per-seat competitors like Doppler).
Brand context:
- Primary color:
#3DD68C (green — intentionally differentiated from Doppler's purple)
- Audience: developers, indie hackers, small teams
- Tone: technical, direct, no fluff
- Stack: TanStack Start (React-based SSR framework), Bun, Turborepo monorepo
When activated, follow this protocol exactly.
STEP 1 — Discover the codebase
Locate all pages and SEO-relevant files. Run these searches in order:
find . -type f \( -name "*.tsx" -o -name "*.ts" \) \
| grep -E "(routes|pages|app)" \
| grep -v node_modules \
| grep -v ".turbo" \
| sort
grep -r "title\|description\|og:\|twitter:\|canonical\|robots\|sitemap\|jsonld\|schema" \
--include="*.tsx" --include="*.ts" --include="*.html" \
-l . | grep -v node_modules
find . -name "robots.txt" -o -name "sitemap.xml" -o -name "sitemap.ts" | grep -v node_modules
grep -r "createMeta\|Meta\|useHead\|<title\|<meta" \
--include="*.tsx" --include="*.ts" \
-l . | grep -v node_modules
Read every file identified. Do not skip any.
STEP 2 — Audit: produce a structured findings table
After reading all files, output a markdown audit table with every page:
| Route | Title | Description | OG Title | OG Desc | OG Image | Twitter Card | Canonical | Robots | Schema | Issues |
|---|
Scoring per cell:
- ✅ Present and optimized
- ⚠️ Present but suboptimal (too long, generic, missing keywords)
- ❌ Missing
Then list critical issues ranked by SEO impact (high → low):
- Missing title tags
- Missing meta descriptions
- Missing Open Graph tags (og:title, og:description, og:image, og:url, og:type)
- Missing Twitter Card tags
- Missing canonical tags
- No structured data (JSON-LD)
- Missing or misconfigured robots.txt
- Missing sitemap
- Missing
<html lang="en">
- Viewport meta tag
- Favicon and apple-touch-icon
STEP 3 — SEO copy strategy for Envy
Before writing any tags, apply these rules to every piece of copy:
Target keywords by page type
Homepage (/)
- Primary:
env file management, secrets manager for developers, dotenv management tool
- Secondary:
.env file sync, team secrets management, doppler alternative
- Intent: awareness + comparison
Pricing (/pricing)
- Primary:
env manager pricing, flat rate secrets manager, doppler alternative pricing
- Secondary:
$19 team secrets, cheap secrets manager
- Intent: decision
Docs / CLI (/docs, /docs/cli)
- Primary:
env CLI tool, pull push env files CLI, envy CLI
- Secondary:
manage dotenv files terminal, env sync command line
- Intent: usage / retention
Login / Signup (/login, /signup)
- No indexing needed — add
noindex, nofollow
Dashboard and app routes (/dashboard, /app/**)
- Add
noindex, nofollow — these are authenticated pages
Copy rules
- Title tags:
{Page Keyword} — Envy format. Max 60 characters. Front-load the keyword.
- Meta descriptions: 140–155 characters. Action-driven. Include primary keyword. End with a soft CTA or differentiator.
- OG titles: can be slightly longer and more conversational than title tags (max 70 chars).
- OG descriptions: 200 chars max. Punchy.
- OG image: use a single shared default OG image at
/og-image.png (1200×630px). Note its absence if missing and instruct to create it.
- Twitter card type:
summary_large_image for all pages.
STEP 4 — TanStack Start meta implementation
TanStack Start uses createFileRoute with a head export for per-route meta. Use this pattern:
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/')({
head: () => ({
meta: [
{ charSet: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ title: 'Envy — Simple .env File Management for Teams' },
{
name: 'description',
content:
'Sync, share, and secure your .env files across your team. Flat $19/month. No per-seat fees. Built for indie hackers and small engineering teams.',
},
{ property: 'og:type', content: 'website' },
{ property: 'og:url', content: 'https://useenvy.dev/' },
{ property: 'og:title', content: 'Envy — Simple .env File Management for Teams' },
{
property: 'og:description',
content:
'Sync, share, and secure your .env files across your team. Flat $19/month — no per-seat pricing.',
},
{ property: 'og:image', content: 'https://useenvy.dev/og-image.png' },
{ property: 'og:image:width', content: '1200' },
{ property: 'og:image:height', content: '630' },
{ property: 'og:site_name', content: 'Envy' },
{ name: 'twitter:card', content: 'summary_large_image' },
{ name: 'twitter:site', content: '@useenvy' },
{ name: 'twitter:title', content: 'Envy — Simple .env File Management for Teams' },
{
name: 'twitter:description',
content:
'Sync, share, and secure your .env files across your team. Flat $19/month — no per-seat pricing.',
},
{ name: 'twitter:image', content: 'https://useenvy.dev/og-image.png' },
{ tagName: 'link', rel: 'canonical', href: 'https://useenvy.dev/' },
{ name: 'robots', content: 'index, follow' },
],
links: [
{ rel: 'icon', href: '/favicon.ico' },
{ rel: 'apple-touch-icon', href: '/apple-touch-icon.png' },
],
}),
component: HomeComponent,
})
For noindex pages (login, dashboard, app routes):
head: () => ({
meta: [
{ title: 'Login — Envy' },
{ name: 'robots', content: 'noindex, nofollow' },
],
}),
For the root layout (__root.tsx) — global defaults:
head: () => ({
meta: [
{ charSet: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ name: 'theme-color', content: '#3DD68C' },
{ property: 'og:site_name', content: 'Envy' },
],
links: [
{ rel: 'icon', href: '/favicon.ico' },
{ rel: 'apple-touch-icon', href: '/apple-touch-icon.png' },
],
}),
STEP 5 — JSON-LD structured data
Add JSON-LD to the homepage and any content-heavy pages. Inject via a <script> tag inside the route component (not in head()):
function HomeStructuredData() {
const schema = {
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: 'Envy',
url: 'https://useenvy.dev',
applicationCategory: 'DeveloperApplication',
operatingSystem: 'Web, macOS, Linux, Windows',
description:
'Secrets and environment variable management for indie hackers and small engineering teams. CLI-first, flat-rate pricing.',
offers: {
'@type': 'Offer',
price: '19',
priceCurrency: 'USD',
billingIncrement: 'monthly',
},
publisher: {
'@type': 'Organization',
name: 'Envy',
url: 'https://useenvy.dev',
},
}
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
)
}
STEP 6 — robots.txt
Check if apps/web/public/robots.txt exists. If not, create it:
User-agent: *
Allow: /
Disallow: /dashboard
Disallow: /app/
Disallow: /api/
Sitemap: https://useenvy.dev/sitemap.xml
STEP 7 — Sitemap
Check if a sitemap exists. If not, create apps/web/src/routes/sitemap.xml.ts:
import { createAPIFileRoute } from '@tanstack/start/api'
const PUBLIC_ROUTES = [
{ path: '/', priority: '1.0', changefreq: 'weekly' },
{ path: '/pricing', priority: '0.9', changefreq: 'monthly' },
{ path: '/docs', priority: '0.8', changefreq: 'weekly' },
{ path: '/docs/cli', priority: '0.8', changefreq: 'weekly' },
{ path: '/blog', priority: '0.7', changefreq: 'weekly' },
]
export const Route = createAPIFileRoute('/sitemap.xml')({
GET: () => {
const base = 'https://useenvy.dev'
const now = new Date().toISOString().split('T')[0]
const urls = PUBLIC_ROUTES.map(
({ path, priority, changefreq }) => `
<url>
<loc>${base}${path}</loc>
<lastmod>${now}</lastmod>
<changefreq>${changefreq}</changefreq>
<priority>${priority}</priority>
</url>`,
).join('')
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls}
</urlset>`
return new Response(xml, {
headers: {
'Content-Type': 'application/xml',
'Cache-Control': 'public, max-age=86400',
},
})
},
})
STEP 8 — Verification checklist
After applying all changes, run this checklist and output pass/fail for each item:
Technical
Open Graph
Twitter
Structured data
Crawl
Assets
STEP 9 — OG image note
If /og-image.png does not exist, flag it explicitly:
⚠️ OG Image missing — Create a 1200×630px image with:
- Background:
#3DD68C (Envy green) or dark #0F1117
- Envy logo / wordmark centered
- Tagline: "Simple .env Management. Flat $19/month."
- White text for contrast
This image is used by Twitter, LinkedIn, Slack, and iMessage previews when anyone shares a link.
Output format
Always end with:
- Audit table (Step 2)
- Issues list ranked by priority
- File-by-file changes — show exact diffs or full file contents for every file that needs to be created or modified
- Verification checklist result (Step 8)
- Next steps — anything outside the scope of meta tags (Core Web Vitals, backlinks, content strategy) flagged as a separate workstream