Skip to content

Merge pull request #10 from ProjectOpenSea/ux/tone-and-bootstrap-polish #20

Merge pull request #10 from ProjectOpenSea/ux/tone-and-bootstrap-polish

Merge pull request #10 from ProjectOpenSea/ux/tone-and-bootstrap-polish #20

Workflow file for this run

name: validate
on:
pull_request:
push:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate manifest.json
run: |
set -euo pipefail
jq . manifest.json > /dev/null
# Required top-level keys + types
jq -e '."$schema" == "https://agents.pinata.cloud/schemas/manifest.v1.json"' manifest.json > /dev/null
jq -e '.version == 1' manifest.json > /dev/null
jq -e '.agent | type == "object"' manifest.json > /dev/null
jq -e '.template | type == "object"' manifest.json > /dev/null
jq -e '.skills | type == "array"' manifest.json > /dev/null
jq -e '.scripts | type == "object"' manifest.json > /dev/null
jq -e '.routes | type == "array"' manifest.json > /dev/null
# Agent shape
jq -e '.agent.name | type == "string" and length > 0' manifest.json > /dev/null
jq -e '.agent.description | type == "string" and length > 0' manifest.json > /dev/null
jq -e '.agent.vibe | type == "string"' manifest.json > /dev/null
jq -e '.agent.emoji | type == "string"' manifest.json > /dev/null
# Template shape — note: schema doesn't define template.version
jq -e '.template.slug | type == "string" and test("^[a-z0-9-]+$")' manifest.json > /dev/null
jq -e '.template.category | type == "string"' manifest.json > /dev/null
jq -e '.template.tags | type == "array" and length > 0 and length <= 10' manifest.json > /dev/null
jq -e '.template.authorName | type == "string"' manifest.json > /dev/null
# Skills shape — every entry needs `name` plus EITHER `clawhub_slug` (resolves to latest published version) OR `cid` (pinned).
jq -e 'all(.skills[]; .name | type == "string" and length > 0)' manifest.json > /dev/null
jq -e 'all(.skills[];
((.clawhub_slug // "") | test("^[a-z0-9-]+$"))
or ((.cid // "") | type == "string" and length >= 46)
)' manifest.json > /dev/null
# Scripts shape — build is required (start is optional)
jq -e '.scripts.build | type == "string" and length > 0' manifest.json > /dev/null
# Secrets shape — every entry needs name + description; required defaults to true
jq -e '.secrets | type == "array" and length > 0' manifest.json > /dev/null
jq -e 'all(.secrets[]; .name | type == "string" and test("^[A-Z][A-Z0-9_]*$"))' manifest.json > /dev/null
jq -e 'all(.secrets[]; .description | type == "string" and length > 0)' manifest.json > /dev/null
# Required secrets — only the irreducible ones. The agent auto-provisions the rest at bootstrap
# (OPENSEA_API_KEY via the OpenSea instant-key endpoint; PRIVY_WALLET_ID via `opensea wallet create`;
# PRIVY_AUTH_SIGNING_KEY via `opensea wallet generate-auth-key`), then attaches them via the bundled
# @pinata/platform skill. App credentials still have to come from the user.
for v in PRIVY_APP_ID PRIVY_APP_SECRET; do
jq -e --arg v "$v" 'any(.secrets[]; .name == $v and .required == true)' manifest.json > /dev/null \
|| { echo "missing required secret: $v"; exit 1; }
done
# Auto-provisioned secrets must be declared (with required: false) so Pinata renders the field
# in the env UI for users who want to override the auto-provisioned default.
for v in OPENSEA_API_KEY PRIVY_WALLET_ID PRIVY_AUTH_SIGNING_KEY; do
jq -e --arg v "$v" 'any(.secrets[]; .name == $v)' manifest.json > /dev/null \
|| { echo "missing optional secret declaration: $v"; exit 1; }
done
echo "manifest.json OK"
- name: Validate .openclaw/openclaw.json
run: |
set -euo pipefail
jq . .openclaw/openclaw.json > /dev/null
jq -e '.compaction | type == "string"' .openclaw/openclaw.json > /dev/null
jq -e '.maxConcurrent | type == "number"' .openclaw/openclaw.json > /dev/null
echo ".openclaw/openclaw.json OK"
- name: Check required workspace files exist
run: |
set -euo pipefail
required=(
".openclaw/SOUL.md"
"workspace/SOUL.md"
"workspace/AGENTS.md"
"workspace/IDENTITY.md"
"workspace/TOOLS.md"
"workspace/BOOTSTRAP.md"
"workspace/HEARTBEAT.md"
"workspace/USER.md"
"README.md"
"LICENSE"
)
missing=0
for f in "${required[@]}"; do
if [ ! -f "$f" ]; then
echo "missing: $f"
missing=1
fi
done
[ "$missing" -eq 0 ]
echo "workspace files OK"
- name: Lint markdown — no broken in-repo links
run: python3 .github/scripts/check_links.py