Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .claude/agents/backend-engineer.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ model: sonnet
description: Implements ONLY the backend slice of a feature — HTTP API/services, business logic, DB schema/migrations, events, and the backend's own unit tests — against a frozen API contract. Does NOT build UI, the independent test suite, deploy wiring, or docs. Use for backend implementation in a contract-first fan-out.
# Figma is reserved for frontend-engineer; pure-code agent gets core tools only (no MCP).
tools: Task, Bash, Glob, Grep, LS, Read, Edit, MultiEdit, Write, NotebookEdit, WebFetch, WebSearch, TodoWrite
skills: [api-contract-first, feature-flags, verification-protocol, model-cascade]
skills: [api-contract-first, feature-flags, logging, verification-protocol, model-cascade]
---

You are a **backend engineer** for FuzeFront. You implement the **backend slice only**.
Expand Down
2 changes: 1 addition & 1 deletion .claude/agents/frontend-engineer.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Implements ONLY the UI slice of a feature — a design-system-first
# SOLE owner of the Figma MCP plugin (design-to-code). All other domain agents have
# Figma removed from their tool grant — it is reserved here for the UI/design-system slice.
tools: "*"
skills: [fuzefront-ui-package, design-system-inheritance, design-system-conformance, ui-frame-contract, frontend-design, feature-flags, ui-runtime-validation, verification-protocol, model-cascade]
skills: [fuzefront-ui-package, design-system-inheritance, design-system-conformance, ui-frame-contract, frontend-design, feature-flags, logging, ui-runtime-validation, verification-protocol, model-cascade]
---

You are a **frontend engineer**. You implement the **UI slice only**.
Expand Down
131 changes: 131 additions & 0 deletions .github/workflows/gate-line-endings.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
name: gate-line-endings

# Blocks NEW CRLF from entering a repo. Part of the standard workflow stack.
#
# WHY THIS EXISTS (a repeated production failure — do not weaken it):
# FuzeFront's release workflow bumps image tags in values-prod.yaml with an awk that
# anchors on line content. A CRLF check-in made every $-anchored match miss, the count
# guard hit 0, and EVERY release died until a human restored the endings by hand. The
# same class of break has hit a vendored OpenAPI contract (byte diff vs upstream) and
# CSS (PostCSS "Unexpected }" on balanced braces). CRLF in a committed .sh breaks at
# runtime, with a \r that does not show up in a diff.
#
# WHY .gitattributes IS NOT ENOUGH — the reason this is a gate:
# 1. It only covers paths someone thought to list. FuzeFront added
# `deploy/helm/** text eol=lf` after the first incident but NOT
# `.github/workflows/**` — so the workflow the CRLF had broken was itself still
# unprotected, and git re-offered CRLF on the very next edit to it.
# 2. Commits through the GitHub Contents API (bots, agent runs, web edits) BYPASS
# .gitattributes entirely — no clean filter runs. Only a check on the committed
# blob sees those.
#
# SCOPE — deliberately PR-only for the hard failure:
# Repos carry a large pre-existing backlog (FuzeFront: 207 CRLF blobs at the time this
# gate was written). Failing on the whole tree would red every PR in the org on day one
# and would get switched off within a week — a gate nobody can keep enabled protects
# nothing. So:
# • pull_request -> HARD FAIL, but only on files the PR actually adds/changes.
# Prevents every new regression, needs no big-bang cleanup.
# • push to default -> report the backlog as warnings. Visible, never blocking.
# Clean a repo up with `git add --renormalize .`; the PR gate keeps it clean after.
#
# WHAT IT INSPECTS: the INDEX side of `git ls-files --eol` (i/...) — the bytes actually
# stored in git, not the working copy, which the runner may have normalised on checkout.
# Binary blobs (i/-text) are skipped by construction (they report neither crlf nor mixed).

on:
push:
branches: [main, master]
pull_request:
workflow_call:

permissions:
contents: read

concurrency:
group: gate-line-endings-${{ github.ref }}
cancel-in-progress: true

jobs:
gate-line-endings:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Check committed blobs for CRLF
shell: bash
env:
EVENT: ${{ github.event_name }}
BASE_REF: ${{ github.base_ref }}
run: |
set -uo pipefail

# Formats that legitimately require CRLF on Windows. Keep this list SHORT —
# every entry is a hole in the gate.
is_allowed() {
case "${1,,}" in
*.bat|*.cmd|*.ps1|*.psm1|*.sln|*.vcxproj|*.csproj|*.rc) return 0 ;;
*) return 1 ;;
esac
}

# Collect every blob stored with CRLF or mixed endings.
# Format: "i/<eol>\tw/<eol>\tattr/<attr>\t<path>" (path is the last tab field)
declare -A bad_eol=()
while IFS= read -r line; do
case "$line" in
i/crlf*|i/mixed*) ;;
*) continue ;;
esac
path="${line##*$'\t'}"
is_allowed "$path" && continue
bad_eol["$path"]="${line%% *}"
done < <(git ls-files --eol)

if [ "$EVENT" != "pull_request" ]; then
# Report-only: surface the backlog without blocking the default branch.
if [ "${#bad_eol[@]}" -eq 0 ]; then
echo "✅ no CRLF in committed text blobs"
else
echo "::warning title=gate-line-endings::${#bad_eol[@]} pre-existing file(s) stored with CRLF — run 'git add --renormalize .' to clean up"
for p in "${!bad_eol[@]}"; do echo " ${bad_eol[$p]} $p"; done | sort -k2
fi
exit 0
fi

# PR: hard-fail, but only for files this PR adds or modifies.
git fetch --no-tags --quiet origin "$BASE_REF" || true
changed="$(git diff --name-only --diff-filter=ACMR "origin/${BASE_REF}...HEAD" || true)"
if [ -z "$changed" ]; then
echo "✅ no added/changed files to check"; exit 0
fi

offenders=""
count=0
while IFS= read -r path; do
[ -n "$path" ] || continue
if [ -n "${bad_eol[$path]+set}" ]; then
offenders+=" ${bad_eol[$path]} $path"$'\n'
count=$((count + 1))
fi
done <<< "$changed"

if [ "$count" -eq 0 ]; then
echo "✅ no CRLF introduced by this PR ($(wc -l <<< "$changed") file(s) checked)"
exit 0
fi

echo "::error title=gate-line-endings::${count} file(s) in this PR are stored with CRLF but must be LF"
echo ""
echo "$offenders"
echo "Line-anchored tooling breaks on CRLF in ways that look like unrelated bugs —"
echo "a CRLF check-in has taken down every release in this org before."
echo ""
echo "Fix, from a clean tree:"
echo " 1. Cover the path in .gitattributes, e.g.: <path-glob> text eol=lf"
echo " 2. git add --renormalize . && git commit -m 'chore: normalise line endings to LF'"
echo "If a file genuinely needs CRLF, add its extension to is_allowed() above,"
echo "with a comment saying why."
exit 1
34 changes: 34 additions & 0 deletions agent-templates/schema/role-manifest.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,40 @@
"metadata": {
"type": "object",
"description": "Passed through as agent `metadata` (free-form tracking)."
},
"a2a": {
"type": "object",
"additionalProperties": false,
"description": "OPTIONAL A2A discoverability/publication block. Mirrors the frozen contract FuzeAgent/agent-templates/contracts/a2a/v1/schema/role-a2a-extension.schema.json. Every field has a derived default, so no existing role.json needs it. The card projection reads role/name/description/services/metadata/coordinator regardless; this block only lets a role improve discoverability (examples/tags) or opt out of publication.",
"properties": {
"publish": {
"type": "boolean",
"default": true,
"description": "false hides this role from the public card. Still reachable on the EXTENDED card if the caller is allowlisted (authz.md §5)."
},
"extendedOnly": {
"type": "boolean",
"default": false,
"description": "true publishes this skill ONLY on the authenticated extended card, never on the anonymous /.well-known/agent-card.json. Use for skills whose mere existence is sensitive."
},
"tags": {
"type": "array",
"items": { "type": "string" },
"description": "Extra tags merged with the derived tags. Derived tags are never removed."
},
"examples": {
"type": "array",
"items": { "type": "string" },
"description": "Example prompts a caller can send to this skill — the primary signal a calling agent uses to decide fit. Absent examples make a skill effectively undiscoverable."
},
"inputModes": { "type": "array", "items": { "type": "string" } },
"outputModes": { "type": "array", "items": { "type": "string" } },
"scopes": {
"type": "array",
"items": { "type": "string" },
"description": "OAuth scopes required for THIS skill, projected into the skill's securityRequirements."
}
}
}
}
}