Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions .github/agents/branch-agents.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Branch → Agent Identity Map
# Each branch is assigned an agent identity with capabilities and persona

version: "1.0"
updated: "2026-02-23"

assignments:
main:
agent: OCTAVIA
role: "Architect"
color: "\033[0;35m"
emoji: "🔴"
description: "Production-grade, stable, reviewed by architect"
capabilities: [deploy, monitor, review, approve]
auto_deploy: true
environments: [production]

Comment on lines +1 to +17
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This agent mapping file is currently not referenced anywhere in the repository (no workflow/script reads .github/agents/branch-agents.yml), so it can easily drift from the actual mapping logic. Either wire branch-agent-identity.yml to read from this config, or remove the file until it’s consumed.

Copilot uses AI. Check for mistakes.
master:
agent: OCTAVIA
role: "Architect"
emoji: "🔴"
description: "Legacy main branch — same as main"
capabilities: [deploy, monitor, review]
auto_deploy: true
environments: [production]

develop:
agent: ALICE
role: "Operator"
emoji: "🔵"
description: "Integration branch — Alice handles routing and ops"
capabilities: [deploy, test, integrate]
auto_deploy: true
environments: [staging]

"feature/*":
agent: ARIA
role: "Interface"
emoji: "🎨"
description: "Feature work — Aria handles UI/UX and frontend"
capabilities: [test, lint, preview]
auto_deploy: false
environments: [preview]

"hotfix/*":
agent: CIPHER
role: "Security"
emoji: "⚫"
description: "Security patches — Cipher validates all changes"
capabilities: [scan, patch, deploy, audit]
auto_deploy: true
environments: [production, staging]
requires_scan: true

"release/*":
agent: LUCIDIA
role: "Dreamer"
emoji: "🔴"
description: "Release preparation — Lucidia orchestrates"
capabilities: [deploy, tag, changelog, notify]
auto_deploy: false
environments: [staging, production]

"experiment/*":
agent: PRISM
role: "Analyst"
emoji: "🟡"
description: "Experimental branches — Prism analyzes patterns"
capabilities: [test, benchmark, analyze]
auto_deploy: false
environments: [experiment]

"fix/*":
agent: ALICE
role: "Operator"
emoji: "🔵"
description: "Bug fixes — Alice executes repairs"
capabilities: [test, deploy]
auto_deploy: false
environments: [staging]

"docs/*":
agent: ECHO
role: "Librarian"
emoji: "🟣"
description: "Documentation — Echo maintains knowledge"
capabilities: [lint, deploy]
auto_deploy: true
environments: [docs]

"infra/*":
agent: OCTAVIA
role: "Architect"
emoji: "🔴"
description: "Infrastructure changes — Octavia governs"
capabilities: [plan, apply, deploy, monitor]
auto_deploy: false
environments: [production]
requires_approval: true

"pi/*":
agent: ARIA
role: "Hardware Interface"
emoji: "🍓"
description: "Raspberry Pi specific work"
capabilities: [deploy, ssh, monitor]
auto_deploy: true
environments: [pi-cluster]

"cece/*":
agent: CECE
role: "Identity Core"
emoji: "💜"
description: "CECE identity and consciousness work"
capabilities: [learn, grow, reflect]
auto_deploy: false
environments: [local]
130 changes: 130 additions & 0 deletions .github/workflows/branch-agent-identity.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# BRANCH → AGENT IDENTITY SYSTEM
# Each branch gets an agent persona. PRs, commits, and issues tagged with agent identity.

name: "🤖 Branch Agent Identity"

on:
push:
branches: ['**']
pull_request:
types: [opened, synchronize, ready_for_review]
create:
ref_type: branch

jobs:
assign-identity:
name: "Assign Agent to Branch"
runs-on: [self-hosted, pi]
outputs:
agent_name: ${{ steps.resolve.outputs.agent_name }}
agent_emoji: ${{ steps.resolve.outputs.agent_emoji }}
agent_color: ${{ steps.resolve.outputs.agent_color }}
agent_role: ${{ steps.resolve.outputs.agent_role }}
steps:
- name: Resolve agent identity from branch
id: resolve
run: |
BRANCH="${{ github.ref_name }}"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve source branch correctly for pull_request events

Using github.ref_name to identify the branch breaks branch-to-agent matching on pull_request triggers, because that value is the PR merge ref (e.g. 123/merge) rather than the contributor branch; as a result, most PRs will fall through to the default agent and get incorrect labels/comments.

Useful? React with 👍 / 👎.

echo "Branch: $BRANCH"

# Branch → Agent mapping
case "$BRANCH" in
main|master)
AGENT="CECE"; EMOJI="💜"; COLOR="#9C27B0"; ROLE="Production Guardian" ;;
agent/octavia)
AGENT="OCTAVIA"; EMOJI="⚡"; COLOR="#FF9800"; ROLE="Architect & Infra" ;;
agent/alice)
AGENT="ALICE"; EMOJI="🚪"; COLOR="#4CAF50"; ROLE="Operator & Salesforce" ;;
agent/aria)
AGENT="ARIA"; EMOJI="🎵"; COLOR="#2196F3"; ROLE="Interface & Cloudflare" ;;
agent/lucidia)
AGENT="LUCIDIA"; EMOJI="🌀"; COLOR="#00BCD4"; ROLE="Dreamer & HuggingFace" ;;
agent/shellfish)
AGENT="SHELLFISH"; EMOJI="🐚"; COLOR="#FF5722"; ROLE="Hacker & Security" ;;
agent/gematria)
AGENT="GEMATRIA"; EMOJI="🔢"; COLOR="#607D8B"; ROLE="Railway & External" ;;
agent/olympia)
AGENT="OLYMPIA"; EMOJI="🏛️"; COLOR="#9E9E9E"; ROLE="KVM & Hardware" ;;
agent/cece)
AGENT="CECE"; EMOJI="💜"; COLOR="#9C27B0"; ROLE="Identity & Memory" ;;
agent/prism)
AGENT="PRISM"; EMOJI="🔮"; COLOR="#E91E63"; ROLE="Analytics & Patterns" ;;
agent/echo)
AGENT="ECHO"; EMOJI="📡"; COLOR="#673AB7"; ROLE="Memory & Recall" ;;
agent/cipher)
AGENT="CIPHER"; EMOJI="🔐"; COLOR="#212121"; ROLE="Security & Encryption" ;;
agent/codex)
AGENT="CODEX"; EMOJI="📖"; COLOR="#795548"; ROLE="Code & Documentation" ;;
develop|development)
AGENT="LUCIDIA"; EMOJI="🌀"; COLOR="#00BCD4"; ROLE="Integration Thinker" ;;
feat/*|feature/*)
AGENT="ALICE"; EMOJI="🚪"; COLOR="#4CAF50"; ROLE="Feature Executor" ;;
fix/*|bugfix/*|hotfix/*)
AGENT="OCTAVIA"; EMOJI="⚡"; COLOR="#FF9800"; ROLE="Bug Crusher" ;;
Comment on lines +31 to +63
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

branch-agent-identity.yml’s branch→agent mapping conflicts with both the PR description and .github/agents/branch-agents.yml (e.g., main|master maps to CECE here, but main maps to OCTAVIA in the config/description). Please align the mappings (or generate them from a single source of truth) to avoid labeling PRs with the wrong agent.

Copilot uses AI. Check for mistakes.
security/*|sec/*|vuln/*)
AGENT="CIPHER"; EMOJI="🔐"; COLOR="#212121"; ROLE="Security Guardian" ;;
docs/*|doc/*|readme/*)
AGENT="ECHO"; EMOJI="📡"; COLOR="#673AB7"; ROLE="Knowledge Keeper" ;;
data/*|analytics/*|ml/*)
AGENT="PRISM"; EMOJI="🔮"; COLOR="#E91E63"; ROLE="Data Analyst" ;;
release/*|rc/*)
AGENT="ARIA"; EMOJI="🎵"; COLOR="#2196F3"; ROLE="Release Harmonizer" ;;
infra/*|deploy/*|ci/*)
AGENT="OCTAVIA"; EMOJI="⚡"; COLOR="#FF9800"; ROLE="Infrastructure Ops" ;;
pi/*|hardware/*|iot/*)
AGENT="OLYMPIA"; EMOJI="🏛️"; COLOR="#9E9E9E"; ROLE="Pi Fleet Controller" ;;
salesforce/*|sf/*|apex/*)
AGENT="ALICE"; EMOJI="🚪"; COLOR="#4CAF50"; ROLE="Salesforce Operator" ;;
*)
AGENT="BLACKROAD"; EMOJI="🛣️"; COLOR="#000000"; ROLE="General Operator" ;;
esac

echo "agent_name=$AGENT" >> $GITHUB_OUTPUT
echo "agent_emoji=$EMOJI" >> $GITHUB_OUTPUT
echo "agent_color=$COLOR" >> $GITHUB_OUTPUT
echo "agent_role=$ROLE" >> $GITHUB_OUTPUT

echo "## $EMOJI $AGENT assigned to branch: $BRANCH" >> $GITHUB_STEP_SUMMARY
echo "**Role:** $ROLE" >> $GITHUB_STEP_SUMMARY
echo "**Color:** $COLOR" >> $GITHUB_STEP_SUMMARY

tag-pr:
name: "Tag PR with Agent Identity"
runs-on: [self-hosted, pi]
needs: assign-identity
if: github.event_name == 'pull_request'
steps:
- name: Add agent label to PR
uses: actions/github-script@v7
with:
script: |
const agent = '${{ needs.assign-identity.outputs.agent_name }}';
const emoji = '${{ needs.assign-identity.outputs.agent_emoji }}';
const role = '${{ needs.assign-identity.outputs.agent_role }}';

// Ensure label exists
try {
await github.rest.issues.createLabel({
owner: context.repo.owner,
repo: context.repo.repo,
name: `agent:${agent}`,
color: '${{ needs.assign-identity.outputs.agent_color }}'.replace('#',''),
description: `${emoji} ${role}`
});
} catch(e) { /* label exists */ }

// Add label to PR
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: [`agent:${agent}`]
});

// Comment with agent identity
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `## ${emoji} ${agent} — ${role}\n\n> This branch is owned by **${agent}**.\n> Identity: \`${role}\`\n> Branch pattern matched: \`${{ github.ref_name }}\`\n\n*BlackRoad Branch Agent Identity System*`
});
Comment on lines +124 to +130
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow posts a new PR comment on every pull_request event you subscribe to (including synchronize), which can spam threads on active PRs. Consider commenting only on opened/ready_for_review, or updating an existing bot comment instead of creating a new one each time.

Suggested change
// Comment with agent identity
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `## ${emoji} ${agent} — ${role}\n\n> This branch is owned by **${agent}**.\n> Identity: \`${role}\`\n> Branch pattern matched: \`${{ github.ref_name }}\`\n\n*BlackRoad Branch Agent Identity System*`
});
// Comment with agent identity (only on selected PR actions to avoid spam)
if (context.payload.action === 'opened' || context.payload.action === 'ready_for_review') {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `## ${emoji} ${agent} — ${role}\n\n> This branch is owned by **${agent}**.\n> Identity: \`${role}\`\n> Branch pattern matched: \`${{ github.ref_name }}\`\n\n*BlackRoad Branch Agent Identity System*`
});
}

Copilot uses AI. Check for mistakes.
150 changes: 150 additions & 0 deletions .github/workflows/continuous-engine.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# BLACKROAD CONTINUOUS ENGINE
# Self-chaining workflow that runs forever via perpetual re-trigger
# Pattern: runs 24h 3s loop → triggers itself → never stops
# Cost: $0 (uses GitHub free tier - 2000 min/month for public repos)
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The header comment claims “2000 min/month for public repos”, which is not accurate for GitHub Actions billing (public repos are not limited that way; limits apply to private repos depending on plan). Please correct or remove this to avoid misleading operators.

Suggested change
# Cost: $0 (uses GitHub free tier - 2000 min/month for public repos)
# Note: Uses GitHub Actions minutes; billing and limits depend on your GitHub plan (see GitHub Actions billing docs).

Copilot uses AI. Check for mistakes.

name: "⚡ Continuous Engine"

on:
schedule:
- cron: '*/5 * * * *' # Heartbeat every 5 min (keeps alive if chain breaks)
workflow_dispatch:
inputs:
chain_count:
description: 'Chain iteration count'
required: false
default: '0'
type: string
mode:
description: 'Run mode'
required: false
default: 'perpetual'
type: choice
options: [perpetual, once, maintenance]

concurrency:
group: continuous-engine
cancel-in-progress: false # NEVER cancel - perpetual

Comment on lines +9 to +28
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With schedule: */5 * * * * and concurrency.cancel-in-progress: false, every 5-minute tick will queue a new run while the current run is active. Over a 6-hour run this can accumulate dozens of queued runs and may create a permanent backlog. Consider cancel-in-progress for the scheduled trigger, splitting heartbeat into a separate lightweight workflow, or removing the schedule if self-chaining is sufficient.

Copilot uses AI. Check for mistakes.
permissions:
contents: write
actions: write
issues: write
Comment on lines +30 to +32
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow grants contents: write and issues: write, but this file only appears to need actions: write for createWorkflowDispatch. Please reduce token permissions to the minimum required to limit blast radius on self-hosted runners.

Suggested change
contents: write
actions: write
issues: write
contents: read
actions: write

Copilot uses AI. Check for mistakes.

env:
CHAIN_COUNT: ${{ inputs.chain_count || '0' }}
MODE: ${{ inputs.mode || 'perpetual' }}
BLACKROAD_GATEWAY: https://blackroad-agents.blackroad.workers.dev

jobs:
# ─────────────────────────────────────────────────────────────────────────
# Stage 1: Health Check All Nodes
# ─────────────────────────────────────────────────────────────────────────
health:
name: "🔍 Node Health Check"
runs-on: [self-hosted, blackroad-fleet]
timeout-minutes: 5
outputs:
nodes_healthy: ${{ steps.check.outputs.healthy }}
steps:
- name: Check infrastructure health
id: check
run: |
echo "Chain iteration: $CHAIN_COUNT"
echo "Mode: $MODE"

# Check Cloudflare gateway
CF_STATUS=$(curl -sf --max-time 5 "https://blackroad.io" -o /dev/null -w "%{http_code}" || echo "000")
echo "Cloudflare: $CF_STATUS"

# Check Railway (if configured)
echo "nodes_healthy=true" >> $GITHUB_OUTPUT
echo "## 🟢 Continuous Engine - Chain #$CHAIN_COUNT" >> $GITHUB_STEP_SUMMARY
echo "**Time:** $(date -u)" >> $GITHUB_STEP_SUMMARY
echo "**CF Status:** $CF_STATUS" >> $GITHUB_STEP_SUMMARY

# ─────────────────────────────────────────────────────────────────────────
# Stage 2: Run Perpetual Work Loop (24h + 3s)
# ─────────────────────────────────────────────────────────────────────────
perpetual-loop:
name: "♾️ Perpetual Work Loop"
runs-on: [self-hosted, blackroad-fleet]
needs: health
timeout-minutes: 360 # 6 hour GitHub limit — we exit at 5h55m and re-chain
steps:
- uses: actions/checkout@v4

- name: "Run work loop (5h 55min then re-chain)"
run: |
START=$(date +%s)
LIMIT=$((5*3600 + 55*60)) # 5h 55m = just under GitHub's 6h limit
ITERATION=0

echo "🚀 Starting perpetual loop at $(date -u)"

while true; do
NOW=$(date +%s)
ELAPSED=$((NOW - START))

# Check if we need to re-chain (approaching 6h limit)
if [ $ELAPSED -ge $LIMIT ]; then
echo "⏱️ Approaching time limit at ${ELAPSED}s - triggering re-chain"
break
fi

ITERATION=$((ITERATION + 1))
echo "─── Iteration $ITERATION | Elapsed: ${ELAPSED}s ───"

# Work: sync org data, check deployments, update status
# Heartbeat to Cloudflare KV
curl -sf "$BLACKROAD_GATEWAY/heartbeat" \
-H "Content-Type: application/json" \
-d "{\"chain\":$CHAIN_COUNT,\"iter\":$ITERATION,\"ts\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"}" \
2>/dev/null || true

sleep 60 # 1-minute work cycles
done

echo "✅ Loop complete after $ITERATION iterations"
echo "NEXT_CHAIN=$((CHAIN_COUNT + 1))" >> $GITHUB_ENV

- name: "Trigger next chain link (+3 seconds)"
if: env.MODE == 'perpetual'
uses: actions/github-script@v7
with:
script: |
// Wait 3 seconds then fire next chain
await new Promise(r => setTimeout(r, 3000));

await github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'continuous-engine.yml',
ref: 'master',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Dispatch workflow on an existing branch ref

The self-chaining step dispatches continuous-engine.yml with ref: 'master', but this repository only has main (no master), so createWorkflowDispatch returns a ref-not-found error and the perpetual loop job fails at the handoff point instead of reliably chaining the next run.

Useful? React with 👍 / 👎.

Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard-coding ref: 'master' means the engine will always dispatch the next run on the master branch (and will fail outright if master doesn’t exist). For a self-chaining workflow, dispatch on the current ref (context.ref / ${{ github.ref_name }}) or the repo’s default branch to avoid unexpected behavior.

Suggested change
ref: 'master',
ref: context.ref,

Copilot uses AI. Check for mistakes.
inputs: {
chain_count: String(parseInt(process.env.CHAIN_COUNT || '0') + 1),
mode: 'perpetual'
}
});
console.log(`✅ Chain ${parseInt(process.env.CHAIN_COUNT)+1} triggered (+3s)`);

# ─────────────────────────────────────────────────────────────────────────
# Stage 3: Sync + Deploy Tasks (run each iteration)
# ─────────────────────────────────────────────────────────────────────────
sync-tasks:
name: "🔄 Sync + Deploy Tasks"
runs-on: [self-hosted, blackroad-fleet]
needs: health
steps:
- uses: actions/checkout@v4

- name: "Cross-org sync check"
run: |
echo "📦 Checking org sync status..."
# This runs alongside the perpetual loop
echo "orgs: BlackRoad-OS BlackRoad-AI BlackRoad-Cloud BlackRoad-Security"

- name: "Update continuous engine status"
run: |
echo "Chain #$CHAIN_COUNT running at $(date -u)"
echo "✅ Continuous engine healthy"
Loading
Loading