Complete reference for all automation scripts included in the tech radar.
- new-blip.ts - Create new blips interactively
- update-status.ts - Update blip ring/status
- import-history.ts - Bulk import history from CSV
- generate.ts - Build the radar
- validate.ts - Validate schemas
Purpose: Interactive CLI for creating new technology blips with proper scaffolding.
npm run new-blip- Blip name: Full technology name (e.g., "Kubernetes", "TypeScript")
- Quadrant: Choose from configured quadrants
- Ring: Choose initial ring (usually Assess for new technologies)
- Summary: One-line description
- Tags: Comma-separated keywords
- Owners: Comma-separated @usernames or @team/names
- Links: Optional external resources
radar/<quadrant>/<slug>.md
With:
- Complete front-matter (all required fields)
- Initial history entry
- Content template with standard sections
- Proper file naming (slug)
π― Create a New Tech Radar Blip
? Blip name: Playwright
? Select quadrant: Tools
? Select ring: Assess
? One-line summary: Modern E2E testing framework
? Tags (comma-separated): testing, e2e, automation
? Owners (comma-separated): @team/quality
? Add external links? Yes
? Link title: Official Docs
? Link URL: https://playwright.dev
? Add another link? No
β
Created: radar/tools/playwright.md
π Next steps:
1. Edit radar/tools/playwright.md to add detailed content
2. Run 'npm run build' to test
3. Create a PR when ready
- File exists: Prevents overwriting existing blips
- Invalid quadrant: Must match radar.config.yml
- Invalid URL: Link URLs must be valid
Purpose: Update a blip's ring/status and automatically append history entries.
npm run update-status <blip-name-or-slug>npm run update-status kubernetes
npm run update-status "trunk based development"
npm run update-status playwright- New ring: Select from Adopt, Trial, Assess, Hold
- Reason for change: Required rationale (stored in history)
- PR number: Optional (e.g., #123)
- Reviewed by: Optional reviewer name
- Finds the blip by name (fuzzy matching)
- Shows current ring and status
- Prompts for new ring
- Auto-detects status:
Moved In: Ring index decreased (closer to Adopt)Moved Out: Ring index increased (further from Adopt)No Change: Same ring
- Updates
ringfield - Updates
statusfield - Appends history entry with:
- Today's date
- New ring
- Rationale
- PR number (if provided)
- Updates
last_reviewedto today
π Searching for "kubernetes"...
β
Found: Kubernetes
Current ring: Trial
Current status: No Change
? Select new ring: Adopt
π‘ Auto-detected status: Moved In
? Reason for change: Production-ready, 15 services migrated successfully
? PR number (e.g., #123, leave empty if none): #412
? Reviewed by (optional, e.g., @username): @tech-lead
β
Updated: radar/platforms/kubernetes.md
Ring: Trial β Adopt
Status: Moved In
History entry added with date 2024-09-15
π Next steps:
1. Review changes in radar/platforms/kubernetes.md
2. Run 'npm run build' to test
3. Create a PR when ready
- Blip not found: Suggests checking spelling
- No change confirmation: Asks before updating if ring unchanged
Purpose: Bulk import historical ring transitions from CSV files.
npm run import-history <csv-file>name,date,ring,note,pr
Kubernetes,2023-06-01,Assess,"Initial evaluation",#123
Kubernetes,2024-01-15,Trial,"Pilot successful",#456
TypeScript,2022-01-01,Adopt,"Org-wide standard",#100Columns:
name: Blip name (must match existing blip)date: YYYY-MM-DD formatring: Adopt | Trial | Assess | Holdnote: Reason for changepr: Optional PR number (#123 format)
- Parses CSV file
- Groups entries by blip name
- For each blip:
- Finds matching file
- Validates history entries with Zod
- Checks for duplicates (by date)
- Merges new entries
- Sorts history chronologically
- Writes back to file
$ npm run import-history history.csv
π₯ Importing history from history.csv...
Found 15 history entries
Processing Kubernetes...
β
Added 3 history entries
Processing TypeScript...
βΉοΈ No new entries to add
Processing React...
β οΈ Could not find blip "React" - skipping
β
Import complete!
Updated: 2 blips
Errors: 1
π Next steps:
1. Review updated files
2. Run 'npm run build' to test
3. Create a PR when ready- File not found: Clear error message
- Invalid CSV: Reports parsing errors
- Blip not found: Skips with warning
- Invalid entry: Zod validation errors shown
- Duplicate dates: Skips existing entries
- Migrating from old radar: Export old data to CSV
- Bulk backfilling: Add historical context to existing blips
- Data recovery: Restore history from backups
Purpose: Main build script that transforms Markdown files into the static radar site.
npm run build// Reads radar.config.yml
// Validates with Zod
// Extracts quadrants, rings, colors, etc.// Finds all radar/**/*.md files
// Parses front-matter with gray-matter
// Validates each blip with Zod
// Checks history consistency
// Generates slug from namea) Zalando entries.json
dist/data/entries.json
Format for radar.js visualization:
{
"entries": [
{
"label": "Kubernetes",
"quadrant": 1,
"ring": 0,
"moved": 1
}
],
"config": { ...radar.config.yml... }
}b) Detail Pages
dist/tech/<slug>/index.html
For each blip:
- Name, quadrant, ring badges
- Summary and metadata
- Links section
- Full Markdown content (rendered)
- History timeline with dates and notes
c) Changelog Page
dist/changelog.html
Shows recent changes (90 days by default):
- New entries
- Moved closer to Adopt
- Moved away from Adopt
d) Index Page
dist/index.html
- Zalando radar visualization
- Side list of all technologies
- Link to changelog
e) Styles
dist/styles.css
- Responsive design
- Timeline styling
- Radar layout
- Badge colors
π Building tech radar...
π Loading configuration...
Title: Tech Radar
Quadrants: Techniques, Platforms, Tools, Languages & Frameworks
Rings: Adopt, Trial, Assess, Hold
π§Ή Cleaning dist directory...
π Parsing markdown files...
Found 8 blips
π― Generating radar data...
Wrote entries.json (8 entries)
π Generating detail pages...
Generated 8 detail pages
π Generating changelog...
Found 12 recent changes
π Generating index page...
π¨ Generating styles...
β
Build complete! Output in dist/
π‘ Preview with: npm run preview
In radar.config.yml:
show_recent_changes_days: 90 # Badge threshold
changelog_days: 90 # Changelog windowPurpose: Validate all blip schemas and check for errors.
npm run validate- Valid YAML syntax
- Required fields present
- Quadrants (exactly 4)
- Rings (exactly 4)
- Colors (valid hex codes)
For each Markdown file:
- Required fields: name, quadrant, ring, status
- Field types: strings, arrays, dates
- Enum values: quadrant/ring/status match config
- Date formats: YYYY-MM-DD
- URL formats: Valid URLs in links
- Latest history ring matches current ring
- History dates in chronological order
- No duplicate dates
π Validating Tech Radar...
β
Configuration valid
β οΈ radar/platforms/kubernetes.md:
Latest history entry shows ring "Trial" but current ring is "Adopt". Please add a history entry or update the ring.
β radar/tools/invalid.md:
quadrant: Expected 'Techniques' | 'Platforms' | 'Tools' | 'Languages & Frameworks', received 'Backend'
since: Date must be in YYYY-MM-DD format
π Validation Summary:
Valid: 7
Warnings: 1
Errors: 1
β Validation failed
0: All validations passed1: Validation errors found
Used in GitHub Actions:
- name: Validate blip schemas
run: npm run validate
continue-on-error: true # Warnings don't fail build# 1. Create blip interactively
npm run new-blip
# 2. Edit content
vi radar/<quadrant>/<slug>.md
# 3. Validate
npm run validate
# 4. Build and preview
npm run build
npm run preview
# 5. Open PR
git add radar/
git commit -m "Add <technology> to radar"
git push origin add-<technology># 1. Update status
npm run update-status "technology-name"
# 2. Update content with learnings
vi radar/<quadrant>/<slug>.md
# 3. Validate and build
npm run validate
npm run build
# 4. Open PR
git commit -am "Move <technology> to <ring>"
git push# 1. Export old radar to CSV
# (external process)
# 2. Import history
npm run import-history old-radar-history.csv
# 3. Review changes
git diff radar/
# 4. Validate and build
npm run validate
npm run build
# 5. Create PR if satisfied
git commit -am "Import historical data"
git pushProblem: update-status or import-history can't find a blip.
Solution:
- Check spelling (case-insensitive, but exact match needed)
- Try the slug:
npm run update-status kubernetes(not "Kubernetes") - Use quotes for multi-word names:
npm run update-status "trunk based development"
Problem: npm run validate reports errors.
Solution:
- Read the error message carefully (shows file and field)
- Check schema in
src/schemas.ts - Common issues:
- Wrong enum value (quadrant, ring, status)
- Invalid date format (must be YYYY-MM-DD)
- Invalid URL format
- Missing required field
Problem: npm run build crashes.
Solution:
- Run
npm run validatefirst - Check for:
- Syntax errors in front-matter (invalid YAML)
- Duplicate blip names
- Invalid history entries
- Check generator logs for specific error
Problem: Validation shows history inconsistency warnings.
Solution:
- These are warnings, not errors
- Update either:
- Current ring to match latest history entry, OR
- Add new history entry explaining ring change
Add to src/schemas.ts:
// Example: Require PR for Adopt ring
export const BlipFrontMatterSchema = z.object({
// ... existing fields ...
}).refine(
(data) => {
if (data.ring === "Adopt" && data.history.length > 0) {
const latest = data.history[data.history.length - 1];
return latest.pr !== undefined;
}
return true;
},
{ message: "Adopt ring requires PR in latest history entry" }
);Extend tools/generate.ts:
// Example: Generate RSS feed
async function generateRSSFeed(blips: BlipWithContent[]) {
const recentBlips = blips
.filter(b => b.status === "New")
.slice(0, 10);
// ... generate RSS XML ...
await fs.outputFile(`${DIST_DIR}/feed.xml`, rss);
}- Documentation: README.md, CONTRIBUTING.md
- Issues: GitHub Issues
- Slack: #tech-radar