Skip to content

v1.6.0 — per-agent souls #14

v1.6.0 — per-agent souls

v1.6.0 — per-agent souls #14

Workflow file for this run

name: Lint and validate
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
markdown-lint:
name: Markdown lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install markdownlint-cli
run: npm install -g markdownlint-cli@0.41.0
- name: Run markdownlint
run: markdownlint '**/*.md' --ignore node_modules --ignore .obsidian --config .markdownlint.jsonc
frontmatter-check:
name: Frontmatter present on all nodes
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check every reference node and subagent starts with frontmatter
run: |
set -e
missing=0
for dir in skills/design-engineering/references skills/design-engineering/agents; do
for f in $(find "$dir" -name '*.md'); do
first_line=$(head -n 1 "$f")
if [ "$first_line" != "---" ]; then
echo "::error file=$f::Missing YAML frontmatter (file must start with ---)"
missing=$((missing + 1))
fi
done
done
if [ $missing -gt 0 ]; then
echo "::error::$missing file(s) missing frontmatter"
exit 1
fi
echo "All reference nodes and subagents have frontmatter."
skill-structure:
name: Skill structure
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Verify required files exist
run: |
set -e
required=(
"skills/design-engineering/SKILL.md"
"skills/design-engineering/agents/README.md"
"skills/design-engineering/agents/ui-reviewer.md"
"skills/design-engineering/agents/motion-auditor.md"
"skills/design-engineering/agents/anti-pattern-scanner.md"
"skills/design-engineering/agents/agentation-fix-loop.md"
"skills/design-engineering/agents/design-md-consumer.md"
"skills/design-engineering/agents/pov-curator.md"
"AGENTS.md"
"SOUL.md"
"README.md"
"LICENSE"
"CONTRIBUTING.md"
"CODE_OF_CONDUCT.md"
"SECURITY.md"
"spec/agent-skills-spec.md"
"template/TEMPLATE.md"
".claude-plugin/marketplace.json"
)
for f in "${required[@]}"; do
if [ ! -f "$f" ]; then
echo "::error file=$f::Required file missing"
exit 1
fi
done
echo "All required files present."
- name: SKILL.md description starts with 'Load when'
run: |
desc=$(awk '/^description:/{flag=1; sub(/^description: /, ""); print; next} flag && /^[a-z]+:/ {flag=0} flag {print}' skills/design-engineering/SKILL.md)
if ! echo "$desc" | head -n 1 | grep -qiE '^["\'']?(load when|use when)'; then
echo "::warning file=skills/design-engineering/SKILL.md::Description should start with 'Load when...' or 'Use when...' per Perplexity's skill-building guide"
else
echo "Description starts with 'Load when' / 'Use when' — OK."
fi
- name: Skill name matches folder name
run: |
name=$(grep -m 1 '^name:' skills/design-engineering/SKILL.md | awk '{print $2}' | tr -d '"')
if [ "$name" != "design-engineering" ]; then
echo "::error::SKILL.md name ($name) does not match folder name (design-engineering)"
exit 1
fi
echo "Name matches folder name."
- name: Subagent frontmatter fields
run: |
set -e
missing=0
for f in $(find skills/design-engineering/agents -name '*.md' -not -name 'README.md'); do
base=$(basename "$f" .md)
# Each subagent must declare: name, description, tools, model
for field in name description tools model; do
if ! grep -qE "^${field}:" "$f"; then
echo "::error file=$f::Subagent missing required frontmatter field: $field"
missing=$((missing + 1))
fi
done
# Subagent name must match filename
agent_name=$(grep -m 1 '^name:' "$f" | awk '{print $2}' | tr -d '"')
if [ "$agent_name" != "$base" ]; then
echo "::error file=$f::Subagent name ($agent_name) does not match filename ($base)"
missing=$((missing + 1))
fi
done
if [ $missing -gt 0 ]; then
echo "::error::$missing subagent frontmatter error(s)"
exit 1
fi
echo "All subagents have required frontmatter (name, description, tools, model) and names match filenames."
- name: Subagent soul block
run: |
set -e
missing=0
for f in $(find skills/design-engineering/agents -name '*.md' -not -name 'README.md'); do
if ! grep -qE '^## Soul' "$f"; then
echo "::error file=$f::Subagent missing required ## Soul section"
missing=$((missing + 1))
fi
done
if [ $missing -gt 0 ]; then
echo "::error::$missing subagent(s) missing ## Soul section"
exit 1
fi
echo "All subagents carry a ## Soul section."
link-check:
name: Internal wikilink check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Verify every [[wikilink]] in skill content resolves to a file
run: |
set -e
# Collect basenames of reference files AND subagents (the resolvable wikilink targets).
# Also include "SKILL" so cross-refs from subagents/README to the main SKILL.md resolve.
basenames=$( { find skills/design-engineering/references skills/design-engineering/agents -name '*.md' -exec basename {} .md \; ; echo SKILL ; } )
# Descriptive uses that aren't real links (allow-list)
allowlist=$(printf '%s\n' wikilinks node-name name foo bar wikilink-1 wikilink-2)
unresolved=0
# Only check actual skill content — not docs (CONTRIBUTING/README/AGENTS/spec/template)
for f in $(find skills/design-engineering -name '*.md'); do
# Strip code fences and inline backticks so descriptive [[wikilinks]] in code don't false-positive.
stripped=$(awk 'BEGIN{infence=0} /^```/{infence=!infence; next} !infence' "$f" | sed 's/`[^`]*`//g')
for link in $(echo "$stripped" | grep -oE '\[\[[a-zA-Z0-9_-]+\]\]' | sed 's/\[\[//;s/\]\]//' | sort -u); do
if echo "$allowlist" | grep -qx "$link"; then
continue
fi
if ! echo "$basenames" | grep -qx "$link"; then
echo "::error file=$f::Unresolved wikilink: [[$link]]"
unresolved=$((unresolved + 1))
fi
done
done
if [ $unresolved -gt 0 ]; then
echo "::error::$unresolved unresolved wikilink(s)"
exit 1
fi
echo "All wikilinks in skill content resolve."