Add OS spec, unification guide, and meta tooling

This commit is contained in:
Alexa Amundson
2025-11-20 12:32:56 -06:00
parent b664885c79
commit d65f41b42f
15 changed files with 595 additions and 592 deletions

324
.github/CODEOWNERS vendored
View File

@@ -1,320 +1,8 @@
# BlackRoad OS Code Owners — Phase Q Edition # Canonical code ownership for BlackRoad OS meta repository
# This file defines module-based ownership with automation awareness. # Keep ownership broad and predictable; satellite repos may define finer rules.
# Each line is a file pattern followed by one or more owners.
#
# Related docs: MERGE_QUEUE_PLAN.md, AUTO_MERGE_POLICY.md, GITHUB_AUTOMATION_RULES.md
# ==============================================================================
# GLOBAL OWNERSHIP
# ==============================================================================
# Default owner for all files (fallback)
* @alexa-amundson * @alexa-amundson
/docs/ @docs-team @alexa-amundson
# ============================================================================== /os-spec/ @infra-team @alexa-amundson
# BACKEND (High Scrutiny) /tools/ @infra-team @alexa-amundson
# ============================================================================== /.github/ @infra-team @alexa-amundson
# Core backend application
/backend/ @alexa-amundson @backend-team
/backend/app/ @alexa-amundson @backend-team
# Backend modules (fine-grained ownership)
/backend/app/routers/ @backend-team @alexa-amundson
/backend/app/models/ @backend-team @data-team @alexa-amundson
/backend/app/services/ @backend-team @alexa-amundson
/backend/app/utils/ @backend-team
# Backend configuration (high scrutiny)
/backend/requirements.txt @alexa-amundson @backend-team
/backend/Dockerfile @alexa-amundson @infra-team
/backend/docker-compose.yml @alexa-amundson @infra-team
/backend/.env.example @alexa-amundson
# Backend tests (low scrutiny, can auto-approve)
/backend/tests/ @backend-team @test-bot
# ==============================================================================
# FRONTEND / OS (Medium Scrutiny)
# ==============================================================================
# Main OS interface (canonical frontend)
/backend/static/ @alexa-amundson @frontend-team
/backend/static/js/ @frontend-team
/backend/static/index.html @alexa-amundson @frontend-team
# Legacy OS interface (being deprecated)
/blackroad-os/ @alexa-amundson @frontend-team
# ==============================================================================
# AGENTS & AUTOMATION (AI-Aware)
# ==============================================================================
# Agent framework
/agents/ @alexa-amundson @agent-team
/agents/base/ @alexa-amundson @agent-team
/agents/categories/ @agent-team
# Agent tests (can auto-approve)
/agents/tests/ @agent-team @test-bot
# ==============================================================================
# INFRASTRUCTURE (Highest Scrutiny — Never Auto-Merge)
# ==============================================================================
# GitHub workflows (manual review required)
/.github/ @alexa-amundson
/.github/workflows/ @alexa-amundson @infra-team
/.github/CODEOWNERS @alexa-amundson
# Infrastructure as code
/infra/ @alexa-amundson @infra-team
/ops/ @alexa-amundson @ops-team @infra-team
# Deployment configuration
railway.toml @alexa-amundson @infra-team
railway.json @alexa-amundson @infra-team
docker-compose.yml @alexa-amundson @infra-team
# CI/CD scripts
/scripts/ @alexa-amundson @ops-team
/scripts/railway/ @alexa-amundson @infra-team
# ==============================================================================
# DOCUMENTATION (Lowest Scrutiny — Can Auto-Merge)
# ==============================================================================
# General documentation (auto-merge eligible)
/docs/ @docs-team
/docs/architecture/ @alexa-amundson @docs-team
# Root-level docs (auto-merge eligible)
/*.md @docs-team
/README.md @alexa-amundson @docs-team
# Security documentation (manual review required)
/SECURITY.md @alexa-amundson
# Phase Q documentation (automation policies)
/MERGE_QUEUE_PLAN.md @alexa-amundson
/AUTO_MERGE_POLICY.md @alexa-amundson
/GITHUB_AUTOMATION_RULES.md @alexa-amundson
/WORKFLOW_BUCKETING_EXPLAINED.md @alexa-amundson
/OPERATOR_PR_EVENT_HANDLERS.md @alexa-amundson
# ==============================================================================
# SDKs (Medium Scrutiny)
# ==============================================================================
# Python SDK
/sdk/python/ @alexa-amundson @sdk-team
/sdk/python/tests/ @sdk-team @test-bot
# TypeScript SDK
/sdk/typescript/ @alexa-amundson @sdk-team
/sdk/typescript/tests/ @sdk-team @test-bot
# ==============================================================================
# OPERATOR & PRISM (Automation Engine)
# ==============================================================================
# GitHub event handlers (critical automation logic)
/backend/app/services/github_events.py @alexa-amundson @operator-team
/backend/app/routers/webhooks.py @alexa-amundson @operator-team
# Prism Console (merge dashboard)
/blackroad-os/js/apps/prism.js @alexa-amundson @prism-team
/blackroad-os/js/apps/prism-merge-dashboard.js @alexa-amundson @prism-team
# ==============================================================================
# RESEARCH & COGNITIVE (Low Scrutiny)
# ==============================================================================
/cognitive/ @alexa-amundson @research-team
/blackroad-universe/ @alexa-amundson @brand-team
/blackroad-universe/prompts/ @alexa-amundson @prompt-team
# ==============================================================================
# STANDARD OPERATING PROCEDURES
# ==============================================================================
/sop/ @alexa-amundson @ops-team
# ==============================================================================
# IMPLEMENTATION PLANS
# ==============================================================================
/implementation-plans/ @alexa-amundson
# ==============================================================================
# TEAM ALIASES (for reference — not enforced by GitHub unless org teams exist)
# ==============================================================================
#
# @alexa-amundson — Primary operator, final authority on all changes
# @backend-team — Backend engineers (alias for automation)
# @frontend-team — Frontend engineers (alias for automation)
# @agent-team — AI agent developers (alias for automation)
# @infra-team — Infrastructure engineers (alias for automation)
# @ops-team — Operations team (alias for automation)
# @sdk-team — SDK developers (alias for automation)
# @docs-team — Documentation writers (alias for automation)
# @prism-team — Prism Console developers (alias for automation)
# @operator-team — Operator Engine developers (alias for automation)
# @research-team — Research team (alias for automation)
# @brand-team — Brand and marketing (alias for automation)
# @prompt-team — Prompt engineers (alias for automation)
# @test-bot — Auto-approval bot for test-only PRs
# @docs-bot — Auto-approval bot for docs-only PRs
#
# NOTE: Some team aliases may not be real GitHub teams. They serve as semantic
# indicators for ownership and automation rules. Auto-approval bots are
# implemented via GitHub Actions, not actual bot accounts.
#
# ==============================================================================
# BlackRoad OS Code Owners
#
# This file defines who is responsible for code in this repository.
# Each line is a file pattern followed by one or more owners.
#
# Ownership hierarchy:
# 1. Human maintainers (primary approval authority)
# 2. AI automation teams (can auto-approve safe changes)
# 3. Specialized reviewers (domain experts)
#
# AI teams are GitHub teams that can auto-merge specific types of PRs:
# - @blackboxprogramming/claude-auto - Claude AI automated changes
# - @blackboxprogramming/atlas-auto - Atlas AI automated changes
# - @blackboxprogramming/docs-auto - Documentation-only changes
# - @blackboxprogramming/test-auto - Test-only changes
# ============================================================================
# GLOBAL OWNERSHIP
# ============================================================================
# All files require approval from primary maintainer
* @alexa-amundson
# ============================================================================
# BACKEND & API
# ============================================================================
# FastAPI Backend
/backend/ @alexa-amundson
/backend/app/ @alexa-amundson
/backend/requirements.txt @alexa-amundson
/backend/Dockerfile @alexa-amundson
# Backend tests can be auto-merged by AI
/backend/tests/ @alexa-amundson @blackboxprogramming/test-auto
/backend/pytest.ini @alexa-amundson @blackboxprogramming/test-auto
# ============================================================================
# FRONTEND & OS
# ============================================================================
# OS Interface (canonical)
/backend/static/ @alexa-amundson
# Legacy standalone UI (deprecated, needs migration)
/blackroad-os/ @alexa-amundson
# ============================================================================
# OPERATOR ENGINE & AUTOMATION
# ============================================================================
# Operator Engine (PR automation, merge queue)
/operator_engine/ @alexa-amundson
/operator_engine/**/*.py @alexa-amundson
# Prism Console (merge dashboard)
/prism-console/ @alexa-amundson
# ============================================================================
# INFRASTRUCTURE & DEVOPS
# ============================================================================
# GitHub Actions & Workflows (critical - no auto-merge)
/.github/workflows/ @alexa-amundson
# GitHub Configuration
/.github/ @alexa-amundson
/.github/CODEOWNERS @alexa-amundson
/.github/dependabot.yml @alexa-amundson @blackboxprogramming/claude-auto
/.github/labeler.yml @alexa-amundson @blackboxprogramming/claude-auto
/.github/merge_queue.yml @alexa-amundson
# Infrastructure scripts
/scripts/ @alexa-amundson
/ops/ @alexa-amundson
/infra/ @alexa-amundson
# Railway deployment (critical - no auto-merge)
railway.toml @alexa-amundson
railway.json @alexa-amundson
# Docker
docker-compose.yml @alexa-amundson
/backend/docker-compose.yml @alexa-amundson
# ============================================================================
# DOCUMENTATION
# ============================================================================
# Core documentation (safe for auto-merge)
/docs/ @alexa-amundson @blackboxprogramming/docs-auto
/README.md @alexa-amundson @blackboxprogramming/docs-auto
/*.md @alexa-amundson @blackboxprogramming/docs-auto
# Implementation plans (AI-generated, can auto-merge)
/implementation-plans/ @alexa-amundson @blackboxprogramming/claude-auto
# ============================================================================
# SDKs
# ============================================================================
# Python SDK
/sdk/python/ @alexa-amundson
/sdk/python/tests/ @alexa-amundson @blackboxprogramming/test-auto
# TypeScript SDK
/sdk/typescript/ @alexa-amundson
/sdk/typescript/tests/ @alexa-amundson @blackboxprogramming/test-auto
# ============================================================================
# AGENTS & AI
# ============================================================================
# AI Agents (can be auto-merged by Claude)
/agents/ @alexa-amundson @blackboxprogramming/claude-auto
/agents/tests/ @alexa-amundson @blackboxprogramming/test-auto
# Prompts & Templates
/blackroad-universe/prompts/ @alexa-amundson @blackboxprogramming/claude-auto
# Cognitive Research
/cognitive/ @alexa-amundson
# ============================================================================
# BRANDING & BUSINESS
# ============================================================================
# BlackRoad Universe (brand, GTM, domains)
/blackroad-universe/ @alexa-amundson
# SOP (Standard Operating Procedures)
/sop/ @alexa-amundson @blackboxprogramming/docs-auto
# ============================================================================
# SPECIAL FILES
# ============================================================================
# Security-sensitive files (no auto-merge ever)
.env.example @alexa-amundson
backend/.env.example @alexa-amundson
SECURITY.md @alexa-amundson
# License
LICENSE @alexa-amundson
# Git configuration
.gitignore @alexa-amundson @blackboxprogramming/claude-auto

25
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,25 @@
---
name: "Bug report"
about: "Report a reproducible issue in a BlackRoad OS service"
labels: [bug]
---
## Summary
<!-- Briefly describe the problem -->
## Steps to Reproduce
1.
2.
3.
## Expected Behavior
## Actual Behavior
## Environment
- Service: <!-- e.g., core, api, operator -->
- Environment: <!-- production / staging / local -->
- Version or commit:
## Additional Context
<!-- Logs, screenshots, or links to failed checks -->

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Operations Handbook
url: https://github.com/blackboxprogramming/BlackRoad-Operating-System/blob/main/IMPLEMENTATION.md
about: Review current implementation notes before filing issues.

View File

@@ -0,0 +1,21 @@
---
name: "Feature request"
about: "Propose an enhancement for a BlackRoad OS service"
labels: [enhancement]
---
## Summary
<!-- What problem should this solve? -->
## Motivation / Use Case
<!-- Who benefits and why? -->
## Proposed Solution
<!-- Outline the desired behavior or API surface -->
## Acceptance Criteria
- [ ]
- [ ]
## Additional Context
<!-- Related docs, diagrams, or references -->

14
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,14 @@
# Summary
<!-- High-level explanation of the change and the services it touches -->
## Checklist
- [ ] Linked the relevant issue or task
- [ ] Updated docs or specs if behavior changed
- [ ] Added or adjusted tests (or noted why not needed)
- [ ] Ran required checks locally (lint/test/build)
## Testing
<!-- List commands run locally, e.g. npm test -->
## Notes
<!-- Deployment impacts, follow-ups, or escalations -->

View File

@@ -1,77 +0,0 @@
# Pull Request
## Description
<!-- Provide a brief description of the changes in this PR -->
## Type of Change
<!-- Mark the relevant option with an 'x' -->
- [ ] 📝 Documentation update
- [ ] 🧪 Tests only
- [ ] 🏗️ Scaffolding/stubs
- [ ] ✨ New feature
- [ ] 🐛 Bug fix
- [ ] ♻️ Refactoring
- [ ] ⚙️ Infrastructure/CI
- [ ] 📦 Dependencies update
- [ ] 🔒 Security fix
- [ ] 💥 Breaking change
## Checklist
<!-- Mark completed items with an 'x' -->
- [ ] Code follows the project's style guidelines
- [ ] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
## Auto-Merge Eligibility
<!-- This section helps determine if this PR qualifies for auto-merge -->
**Eligible for auto-merge?**
- [ ] Yes - This is a docs-only, tests-only, or small AI-generated PR
- [ ] No - Requires human review
**Reason for auto-merge eligibility:**
- [ ] Docs-only (Tier 1)
- [ ] Tests-only (Tier 2)
- [ ] Scaffolding < 200 lines (Tier 3)
- [ ] AI-generated < 500 lines (Tier 4)
- [ ] Dependency patch/minor (Tier 5)
**If not auto-merge eligible, why?**
- [ ] Breaking change
- [ ] Security-related
- [ ] Infrastructure changes
- [ ] Requires discussion
- [ ] Large PR (> 500 lines)
## Related Issues
<!-- Link to related issues -->
Closes #
Related to #
## Test Plan
<!-- Describe how you tested these changes -->
## Screenshots (if applicable)
<!-- Add screenshots for UI changes -->
---
**Note**: This PR will be automatically labeled based on files changed. See `GITHUB_AUTOMATION_RULES.md` for details.
If this PR meets auto-merge criteria (see `AUTO_MERGE_POLICY.md`), it will be automatically approved and merged after checks pass.
For questions about the merge queue system, see `MERGE_QUEUE_PLAN.md`.

View File

@@ -1,206 +1,26 @@
name: BlackRoad OS CI name: CI
on: on:
push: push:
branches: [ "main" ] branches: [main]
pull_request: pull_request:
branches: [ "main" ]
workflow_dispatch: permissions:
contents: read
jobs: jobs:
validate: build-and-test:
name: Validate HTML & JavaScript
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
UI_ENTRY: backend/static/index.html
steps: steps:
- name: Checkout repository - uses: actions/checkout@v4
uses: actions/checkout@v4 - name: Use Node.js
uses: actions/setup-node@v4
- name: Setup Python
uses: actions/setup-python@v4
with: with:
python-version: '3.11' node-version: 20
cache: 'npm'
- name: Validate HTML structure - name: Install dependencies
run: | run: npm ci
echo "🔍 Validating HTML structure..." - name: Type check
python3 << 'EOF' run: npm run build
import os - name: Tests
import sys run: npm test
import re
def validate_html(filename):
errors = []
warnings = []
try:
with open(filename, 'r') as f:
content = f.read()
except FileNotFoundError:
print(f" No {filename} found - skipping validation")
return True
# Check basic structure
if not content.strip().startswith('<!DOCTYPE html>'):
errors.append("Missing DOCTYPE declaration")
if '<html' not in content or '</html>' not in content:
errors.append("Missing html tags")
if '<head>' not in content or '</head>' not in content:
errors.append("Missing head tags")
if '<body>' not in content or '</body>' not in content:
errors.append("Missing body tags")
# Check for unclosed tags
script_opens = content.count('<script')
script_closes = content.count('</script>')
if script_opens != script_closes:
errors.append(f"Mismatched script tags: {script_opens} opens, {script_closes} closes")
div_opens = content.count('<div')
div_closes = content.count('</div>')
if div_opens != div_closes:
errors.append(f"Mismatched div tags: {div_opens} opens, {div_closes} closes")
style_opens = content.count('<style>')
style_closes = content.count('</style>')
if style_opens != style_closes:
errors.append(f"Mismatched style tags: {style_opens} opens, {style_closes} closes")
# Report results
print(f"\n{'='*60}")
print(f"HTML Validation Results: {filename}")
print(f"{'='*60}")
print(f"File size: {len(content):,} bytes")
print(f"Lines: {content.count(chr(10)):,}")
print(f"Divs: {div_opens} opens, {div_closes} closes")
print(f"Scripts: {script_opens} opens, {script_closes} closes")
print(f"Styles: {style_opens} opens, {style_closes} closes")
if errors:
print(f"\n❌ ERRORS FOUND ({len(errors)}):")
for i, error in enumerate(errors, 1):
print(f" {i}. {error}")
return False
else:
print("\n✅ All validation checks passed!")
return True
# Validate canonical UI entrypoint
target = os.environ.get('UI_ENTRY', 'backend/static/index.html')
valid = validate_html(target)
sys.exit(0 if valid else 1)
EOF
- name: Check JavaScript syntax
run: |
echo "🔍 Checking JavaScript syntax..."
if [ -f "$UI_ENTRY" ]; then
# Extract and check JavaScript
python3 << 'EOF'
import os
import re
import sys
target = os.environ.get('UI_ENTRY', 'backend/static/index.html')
with open(target, 'r') as f:
content = f.read()
# Extract JavaScript code
script_match = re.search(r'<script>(.*?)</script>', content, re.DOTALL)
if not script_match:
print(" No inline JavaScript found")
sys.exit(0)
js_code = script_match.group(1)
# Basic syntax checks
issues = []
# Check for common syntax errors
if js_code.count('{') != js_code.count('}'):
issues.append(f"Mismatched braces: {js_code.count('{')} opens, {js_code.count('}')} closes")
if js_code.count('(') != js_code.count(')'):
issues.append(f"Mismatched parentheses: {js_code.count('(')} opens, {js_code.count(')')} closes")
if js_code.count('[') != js_code.count(']'):
issues.append(f"Mismatched brackets: {js_code.count('[')} opens, {js_code.count(']')} closes")
# Check for basic structure
functions = len(re.findall(r'function\s+\w+', js_code))
print(f"\n{'='*60}")
print(f"JavaScript Syntax Check")
print(f"{'='*60}")
print(f"Code size: {len(js_code):,} bytes")
print(f"Functions declared: {functions}")
print(f"Braces: {js_code.count('{')} matched pairs")
print(f"Parentheses: {js_code.count('(')} matched pairs")
print(f"Brackets: {js_code.count('[')} matched pairs")
if issues:
print(f"\n❌ SYNTAX ISSUES ({len(issues)}):")
for i, issue in enumerate(issues, 1):
print(f" {i}. {issue}")
sys.exit(1)
else:
print("\n✅ JavaScript syntax appears valid!")
sys.exit(0)
EOF
else
echo " No UI entrypoint found - skipping JS validation"
fi
- name: Check for common security issues
run: |
echo "🔒 Checking for security issues..."
if [ -f "$UI_ENTRY" ]; then
# Check for inline event handlers with user input (basic XSS check)
if grep -i "eval(" "$UI_ENTRY"; then
echo "⚠️ Warning: Found eval() - potential security risk"
# Not failing for this, just warning
fi
if grep -i "innerHTML.*user" "$UI_ENTRY"; then
echo "⚠️ Warning: Found innerHTML with user input - potential XSS risk"
fi
echo "✅ Basic security checks completed"
else
echo " No UI entrypoint found - skipping security checks"
fi
- name: Validate README
run: |
echo "📄 Checking README..."
if [ -f "README.md" ]; then
word_count=$(wc -w < README.md)
line_count=$(wc -l < README.md)
echo "README.md: $line_count lines, $word_count words"
if [ $word_count -lt 50 ]; then
echo "⚠️ README is quite short (< 50 words)"
else
echo "✅ README is comprehensive"
fi
else
echo "❌ No README.md found!"
exit 1
fi
- name: Summary
if: success()
run: |
echo ""
echo "╔════════════════════════════════════════════════════════╗"
echo "║ ║"
echo "║ ✅ All BlackRoad OS validation checks passed! ║"
echo "║ ║"
echo "║ The code is ready for deployment to GitHub Pages. ║"
echo "║ ║"
echo "╚════════════════════════════════════════════════════════╝"
echo ""

View File

@@ -9,6 +9,16 @@ It unifies humans, agents, and infrastructure into a single operating system for
![Version](https://img.shields.io/badge/version-1.0-blue) ![Version](https://img.shields.io/badge/version-1.0-blue)
![License](https://img.shields.io/badge/license-MIT-green) ![License](https://img.shields.io/badge/license-MIT-green)
## Meta / Orchestrator repo
This repository is the canonical, meta-level source of truth for BlackRoad OS. It holds shared specs, governance docs, CI standards, and lightweight tooling only. Deployable runtime code lives in the satellite repositories referenced in the OS spec.
- **OS spec:** Machine-readable registry at [`os-spec/os-spec.json`](os-spec/os-spec.json) with a short overview in [`docs/OS_SPEC.md`](docs/OS_SPEC.md).
- **Repo unification standard:** Authoritative conventions for satellite repos in [`docs/REPO_UNIFICATION.md`](docs/REPO_UNIFICATION.md).
- **Health dashboard:** Local CLI that pings each services `/health` endpoint (`npm run check:health`).
> This repo should remain meta-only. Do not deploy it directly; deploy the satellite services instead.
## Core Entities ## Core Entities
- **Alexa Louise Amundson ("Alexa", "Cadillac")** - **Alexa Louise Amundson ("Alexa", "Cadillac")**
@@ -62,6 +72,17 @@ All BlackRoad services, apps, and docs now live in this monorepo and sync out au
The mapping is machine-readable at `infra/github/sync-config.yml`, and the sync process is documented in `docs/os/monorepo-sync.md`. The mapping is machine-readable at `infra/github/sync-config.yml`, and the sync process is documented in `docs/os/monorepo-sync.md`.
## Health dashboard (local)
Run the lightweight status CLI against all satellite services defined in the OS spec:
```bash
npm install
npm run check:health
```
The script reads `os-spec/os-spec.json` and prints a status table. It is intended for operator use; production monitoring should still live in deployed observability stacks.
## Features ## Features
### 🤖 AI & Communication ### 🤖 AI & Communication

16
docs/OS_SPEC.md Normal file
View File

@@ -0,0 +1,16 @@
# BlackRoad OS Spec
This repository holds the canonical service registry for BlackRoad OS. The machine-readable source of truth lives in [`os-spec/os-spec.json`](../os-spec/os-spec.json) and is designed to be imported by automation, dashboards, and deployment tooling.
## Fields
Each entry under `services` defines one OS component with the following fields:
- **key**: Stable identifier used by tooling.
- **name**: Human-readable service name.
- **repoUrl**: Canonical GitHub repository for the service.
- **railwayUrl**: Production Railway hostname for runtime health checks.
- **cloudflareSubdomain**: Public DNS entry managed through Cloudflare.
- **healthPath**: Path segment appended to the base URL for health monitoring.
New services should extend the JSON file using the same shape so that dashboards and scripts can discover them automatically.

64
docs/REPO_UNIFICATION.md Normal file
View File

@@ -0,0 +1,64 @@
# Repository Unification Standard
All BlackRoad OS services follow the same surface area so automation, monitoring, and deployment can treat them consistently. This document is the authoritative guide for new and existing satellite repositories.
## Required HTTP routes
- `GET /health` Returns a JSON payload with service status, dependency checks, and timestamp.
- `GET /version` Returns service name, semantic version, git commit, and build timestamp.
## Configuration loader pattern
Every service should expose a single configuration entry point that:
1. Reads environment variables once at boot.
2. Validates required keys with defaults for optional settings.
3. Exports a typed object consumed across the codebase.
Recommended pattern (TypeScript/Python pseudocode):
```ts
// config.ts
export interface ServiceConfig {
env: 'production' | 'staging' | 'development';
port: number;
railwayStaticUrl?: string;
cloudflareUrl?: string;
}
export function loadConfig(): ServiceConfig {
const env = process.env.NODE_ENV ?? 'development';
const port = Number(process.env.PORT ?? '8000');
return {
env: env as ServiceConfig['env'],
port,
railwayStaticUrl: process.env.RAILWAY_STATIC_URL,
cloudflareUrl: process.env.CLOUDFLARE_URL,
};
}
```
Services in other languages should mirror this approach: centralize parsing, validate eagerly, and share a typed structure.
## `railway.json` fields
Every deployable repo should ship a `railway.json` (or equivalent environment manifest) containing at minimum:
- `projectId`: Railway project identifier.
- `serviceId`: Specific service identifier within the project.
- `env`: Deployment environment (`production`, `staging`, or `development`).
- `healthcheckPath`: Path used by Railway health probes (must match `/health`).
- `staticUrl`: The generated `RAILWAY_STATIC_URL` for reference in automation.
## Minimal `package.json` scripts
For JavaScript/TypeScript services, include these scripts even if they wrap simple commands:
- `dev`: Local development entry point (e.g., `next dev`, `nodemon src/index.ts`).
- `build`: Compile or bundle step.
- `start`: Production start command using the build output.
- `lint`: Static analysis or formatting checks.
- `test`: Unit or integration tests; may temporarily be a placeholder until coverage improves.
Consistency across repositories allows shared CI workflows and the global health dashboard to operate without per-repo customization.

61
os-spec/os-spec.json Normal file
View File

@@ -0,0 +1,61 @@
{
"version": "2025-03-01",
"services": [
{
"key": "core",
"name": "Core API",
"repoUrl": "https://github.com/BlackRoad-OS/blackroad-os-core",
"railwayUrl": "https://9gw4d0h2.up.railway.app",
"cloudflareSubdomain": "https://core.blackroad.systems",
"healthPath": "/health"
},
{
"key": "api",
"name": "Public API",
"repoUrl": "https://github.com/BlackRoad-OS/blackroad-os-api",
"railwayUrl": "https://ac7bx15h.up.railway.app",
"cloudflareSubdomain": "https://api.blackroad.systems",
"healthPath": "/health"
},
{
"key": "agents",
"name": "Agents Runtime",
"repoUrl": "https://github.com/blackboxprogramming/blackroad-operator",
"railwayUrl": null,
"cloudflareSubdomain": "https://agents.blackroad.systems",
"healthPath": "/health"
},
{
"key": "operator",
"name": "Operator Orchestrator",
"repoUrl": "https://github.com/BlackRoad-OS/blackroad-os-operator",
"railwayUrl": "https://blackroad-os-operator-production-3983.up.railway.app",
"cloudflareSubdomain": "https://operator.blackroad.systems",
"healthPath": "/health"
},
{
"key": "prism-console",
"name": "Prism Console",
"repoUrl": "https://github.com/BlackRoad-OS/blackroad-os-prism-console",
"railwayUrl": "https://qqr1r4hd.up.railway.app",
"cloudflareSubdomain": "https://console.blackroad.systems",
"healthPath": "/health"
},
{
"key": "web",
"name": "Marketing Web",
"repoUrl": "https://github.com/BlackRoad-OS/blackroad-os-web",
"railwayUrl": "https://blackroad-os-web-production-3bbb.up.railway.app",
"cloudflareSubdomain": "https://web.blackroad.systems",
"healthPath": "/health"
},
{
"key": "docs",
"name": "Documentation Site",
"repoUrl": "https://github.com/BlackRoad-OS/blackroad-os-docs",
"railwayUrl": "https://2izt9kog.up.railway.app",
"cloudflareSubdomain": "https://docs.blackroad.systems",
"healthPath": "/health"
}
]
}

235
package-lock.json generated Normal file
View File

@@ -0,0 +1,235 @@
{
"name": "blackroad-operating-system-meta",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "blackroad-operating-system-meta",
"version": "0.1.0",
"devDependencies": {
"@types/node": "^20.12.7",
"ts-node": "^10.9.2",
"typescript": "^5.4.3"
}
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/trace-mapping": "0.3.9"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@tsconfig/node10": {
"version": "1.0.12",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz",
"integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node12": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
"dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node14": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
"dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node16": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/node": {
"version": "20.19.25",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz",
"integrity": "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/acorn": {
"version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/acorn-walk": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
"dev": true,
"license": "MIT",
"dependencies": {
"acorn": "^8.11.0"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true,
"license": "MIT"
},
"node_modules/create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true,
"license": "MIT"
},
"node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true,
"license": "ISC"
},
"node_modules/ts-node": {
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"v8-compile-cache-lib": "^3.0.1",
"yn": "3.1.1"
},
"bin": {
"ts-node": "dist/bin.js",
"ts-node-cwd": "dist/bin-cwd.js",
"ts-node-esm": "dist/bin-esm.js",
"ts-node-script": "dist/bin-script.js",
"ts-node-transpile-only": "dist/bin-transpile.js",
"ts-script": "dist/bin-script-deprecated.js"
},
"peerDependencies": {
"@swc/core": ">=1.2.50",
"@swc/wasm": ">=1.2.50",
"@types/node": "*",
"typescript": ">=2.7"
},
"peerDependenciesMeta": {
"@swc/core": {
"optional": true
},
"@swc/wasm": {
"optional": true
}
}
},
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"dev": true,
"license": "MIT"
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
"dev": true,
"license": "MIT"
},
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
}
}
}

18
package.json Normal file
View File

@@ -0,0 +1,18 @@
{
"name": "blackroad-operating-system-meta",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "echo \"No runtime app in meta repo\"",
"build": "tsc --noEmit",
"start": "echo \"Meta repo has no start command\"",
"lint": "eslint . --ext .ts,.js || true",
"test": "echo \"No automated tests yet\"",
"check:health": "ts-node tools/health-check.ts"
},
"devDependencies": {
"@types/node": "^20.12.7",
"ts-node": "^10.9.2",
"typescript": "^5.4.3"
}
}

79
tools/health-check.ts Normal file
View File

@@ -0,0 +1,79 @@
import fs from 'fs';
import path from 'path';
import { setTimeout as delay } from 'timers/promises';
type ServiceEntry = {
key: string;
name: string;
repoUrl: string;
railwayUrl?: string | null;
cloudflareSubdomain?: string | null;
healthPath?: string;
};
type OsSpec = {
version: string;
services: ServiceEntry[];
};
const SPEC_PATH = path.resolve(__dirname, '..', 'os-spec', 'os-spec.json');
const DEFAULT_TIMEOUT_MS = 8000;
function loadSpec(): OsSpec {
const raw = fs.readFileSync(SPEC_PATH, 'utf-8');
return JSON.parse(raw) as OsSpec;
}
function buildHealthUrl(service: ServiceEntry): string | null {
const base = service.cloudflareSubdomain ?? service.railwayUrl;
if (!base) return null;
const normalizedBase = base.endsWith('/') ? base.slice(0, -1) : base;
const pathPart = service.healthPath ?? '/health';
return `${normalizedBase}${pathPart.startsWith('/') ? '' : '/'}${pathPart}`;
}
async function checkHealth(url: string): Promise<{ status: string; detail: string }> {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);
try {
const response = await fetch(url, { signal: controller.signal });
const bodyText = await response.text();
const statusLabel = response.ok ? 'healthy' : 'unhealthy';
return { status: statusLabel, detail: `${response.status} ${response.statusText}` };
} catch (error) {
const reason = (error as Error).message;
return { status: 'unreachable', detail: reason };
} finally {
clearTimeout(timeout);
}
}
async function main() {
const spec = loadSpec();
const results: Array<{ service: string; target: string; status: string; detail: string }> = [];
for (const service of spec.services) {
const url = buildHealthUrl(service);
if (!url) {
results.push({ service: service.key, target: 'N/A', status: 'skipped', detail: 'No target URL defined' });
continue;
}
const { status, detail } = await checkHealth(url);
results.push({ service: service.key, target: url, status, detail });
await delay(50); // small pause to avoid overwhelming endpoints
}
console.table(results);
const failures = results.filter((row) => row.status !== 'healthy' && row.status !== 'skipped');
if (failures.length > 0) {
console.error(`\nHealth check completed with ${failures.length} issue(s).`);
process.exitCode = 1;
}
}
main().catch((error) => {
console.error('Unexpected error while running health checks', error);
process.exitCode = 1;
});

13
tsconfig.json Normal file
View File

@@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "ES2021",
"module": "CommonJS",
"moduleResolution": "Node",
"esModuleInterop": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"types": ["node"],
"lib": ["ES2021", "DOM"]
},
"include": ["tools/**/*.ts", "os-spec/**/*.json"]
}