Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d238ec7ff9 | ||
|
|
98f8b8f7b0 | ||
|
|
2d936369b4 | ||
|
|
41c0469a60 | ||
|
|
f140f6d83d | ||
|
|
03a55fb8f7 | ||
|
|
b9acb415aa | ||
|
|
e47b15169e | ||
|
|
c1d439f83c | ||
|
|
9cafb7c376 | ||
|
|
0acbc866cf | ||
|
|
b01216e6ed | ||
|
|
c6a9d37840 | ||
|
|
5266bc6456 | ||
|
|
b53ab3f6ad | ||
|
|
f5fe3ff444 | ||
|
|
5538ff53b8 | ||
|
|
2f8439e23e | ||
|
|
7aae2d0ce5 | ||
|
|
4e8815069c | ||
|
|
787f71d3ed | ||
|
|
af7a8930e8 | ||
|
|
b75dfa14b8 | ||
|
|
66fe641c0e | ||
|
|
66de47afcb | ||
|
|
9647ec07ca | ||
|
|
4398c5061e | ||
|
|
fe849db257 | ||
|
|
8a3561c551 | ||
|
|
8712206499 | ||
|
|
ca8ec4e92c | ||
|
|
25df458b5d | ||
|
|
598e495175 | ||
|
|
18f50c85ea | ||
|
|
021b9ad2e8 | ||
|
|
1c13c5b7a3 | ||
|
|
b0035d7771 | ||
|
|
6b451bf47e | ||
|
|
e9ffcab695 | ||
|
|
836d575374 | ||
|
|
8f01ec8ed8 | ||
|
|
baabfa40b5 | ||
|
|
7cf1043fae | ||
|
|
845fc5050d | ||
|
|
a4972acb93 | ||
|
|
6069fc3f07 | ||
|
|
5ea6905b19 | ||
|
|
8acfa5aa78 | ||
|
|
3d315c96dd | ||
|
|
9dcf246bc2 | ||
|
|
0d1b14faf5 | ||
|
|
74d346f5a2 | ||
|
|
e86050b1bc | ||
|
|
07791fe470 | ||
|
|
de1d1dc848 | ||
|
|
a7a537aac0 | ||
|
|
618400f40c | ||
|
|
66e762fe87 | ||
|
|
3674dd72ca | ||
|
|
d8549a7ac3 | ||
|
|
8f7bba35ff | ||
|
|
b434eb4c83 | ||
|
|
7f4107ba81 | ||
|
|
9ee3d3ffad | ||
|
|
d683d05a3c | ||
|
|
099f002089 | ||
|
|
9e6d801418 | ||
|
|
538c2c0713 | ||
|
|
3ad8006f64 | ||
|
|
6e986b1e41 | ||
|
|
4dbc18e490 | ||
|
|
4c7ec72c8e | ||
|
|
5cba745702 | ||
|
|
aa6fa9d39c | ||
|
|
6f5a5312bc | ||
|
|
7b7bd713e3 | ||
|
|
84bb6339a8 | ||
|
|
55b3a9dbe3 | ||
|
|
406d02599c | ||
|
|
1f29641fb3 | ||
|
|
f048c9adc0 | ||
|
|
8c62dc88f1 | ||
|
|
1d75ea93f4 | ||
|
|
c83dc7a42c | ||
|
|
88ef239b76 | ||
|
|
221ff269fd | ||
|
|
07ebe1e23e | ||
|
|
d6786c1ef1 | ||
|
|
7ed0334696 | ||
|
|
0fc7fb2993 | ||
|
|
62676305da | ||
|
|
5999247584 | ||
|
|
5ac1acef42 | ||
|
|
0188f16f04 | ||
|
|
297e95b9a4 | ||
|
|
26af383cf8 | ||
|
|
47c519ba69 | ||
|
|
a7c82ecd88 | ||
|
|
fa8864e49d | ||
|
|
2339a744d4 | ||
|
|
69d5ef4c72 | ||
|
|
bd4762be9f | ||
|
|
beaa5aecad | ||
|
|
8fdb9224b2 | ||
|
|
99790afd64 | ||
|
|
93f57b6c83 | ||
|
|
c148e51c1a | ||
|
|
7f51db60eb | ||
|
|
8e8227978c | ||
|
|
0da9bce27c | ||
|
|
e0e4def7e0 | ||
|
|
75b4af13ac | ||
|
|
33a47200f1 | ||
|
|
c4c142b6fa | ||
|
|
b8eee3a668 | ||
|
|
4222a94ad9 | ||
|
|
94027972d8 | ||
|
|
91601c2395 | ||
|
|
623c77c9e3 | ||
|
|
cb1b807d22 | ||
|
|
8f8e07c270 | ||
|
|
5cc7e02544 | ||
|
|
90e4e7ee9b | ||
|
|
95be288c27 | ||
|
|
d5305b3d78 | ||
|
|
1caec236fa | ||
|
|
14e71d6b4a | ||
|
|
5918258de9 | ||
|
|
a7561c8b6c | ||
|
|
92ccdf82be | ||
|
|
47a7a8db80 | ||
|
|
353ee15fce | ||
|
|
346da20fe4 | ||
|
|
8c6db59def | ||
|
|
39ee8b1d24 | ||
|
|
e5b86164e1 |
@@ -1,19 +0,0 @@
|
||||
# Frontend
|
||||
VITE_CONVEX_URL=
|
||||
VITE_CONVEX_SITE_URL=
|
||||
VITE_SOULHUB_SITE_URL=
|
||||
VITE_SOULHUB_HOST=
|
||||
VITE_SITE_MODE=
|
||||
SITE_URL=http://localhost:3000
|
||||
CONVEX_SITE_URL=
|
||||
|
||||
# Convex Auth (GitHub OAuth App)
|
||||
AUTH_GITHUB_ID=
|
||||
AUTH_GITHUB_SECRET=
|
||||
|
||||
# Convex Auth JWT keys (generated via @convex-dev/auth CLI)
|
||||
JWT_PRIVATE_KEY=
|
||||
JWKS=
|
||||
|
||||
# Embeddings
|
||||
OPENAI_API_KEY=
|
||||
@@ -1,41 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 15
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: oven-sh/setup-bun@e3914758a49697077f7bcd190d36582a61667aad
|
||||
with:
|
||||
bun-version: 1.3.10
|
||||
|
||||
- name: Install
|
||||
run: bun install --frozen-lockfile
|
||||
- name: Peer deps
|
||||
run: bun run check:peers
|
||||
|
||||
- name: Lint
|
||||
run: bun run lint
|
||||
|
||||
- name: Test
|
||||
run: bun run test
|
||||
|
||||
- name: Coverage
|
||||
run: bun run coverage
|
||||
|
||||
- name: Typecheck
|
||||
run: |
|
||||
bunx tsc --noEmit
|
||||
bunx tsc -p packages/schema/tsconfig.json --noEmit
|
||||
bunx tsc -p packages/clawdhub/tsconfig.json --noEmit
|
||||
|
||||
- name: Build
|
||||
run: bun run build
|
||||
@@ -1,138 +0,0 @@
|
||||
name: Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: deploy-production
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
preflight-secrets:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
CONVEX_DEPLOY_KEY: ${{ secrets.CONVEX_DEPLOY_KEY }}
|
||||
PLAYWRIGHT_AUTH_STORAGE_STATE_JSON: ${{ secrets.PLAYWRIGHT_AUTH_STORAGE_STATE_JSON }}
|
||||
steps:
|
||||
- name: Check deploy secrets
|
||||
run: |
|
||||
missing=()
|
||||
|
||||
if [[ -z "$CONVEX_DEPLOY_KEY" ]]; then
|
||||
missing+=("CONVEX_DEPLOY_KEY")
|
||||
fi
|
||||
|
||||
if (( ${#missing[@]} > 0 )); then
|
||||
echo "::error::Missing required GitHub Actions secrets: ${missing[*]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$PLAYWRIGHT_AUTH_STORAGE_STATE_JSON" ]]; then
|
||||
echo "PLAYWRIGHT_AUTH_STORAGE_STATE_JSON not set; authenticated smoke will be skipped."
|
||||
fi
|
||||
|
||||
deploy-convex:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
needs: preflight-secrets
|
||||
env:
|
||||
CONVEX_DEPLOY_KEY: ${{ secrets.CONVEX_DEPLOY_KEY }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: oven-sh/setup-bun@e3914758a49697077f7bcd190d36582a61667aad
|
||||
with:
|
||||
bun-version: 1.3.10
|
||||
|
||||
- name: Install
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Stamp Convex build SHA
|
||||
run: bunx convex env set APP_BUILD_SHA "${GITHUB_SHA}" --prod
|
||||
|
||||
- name: Stamp Convex deploy time
|
||||
run: bunx convex env set APP_DEPLOYED_AT "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" --prod
|
||||
|
||||
- name: Deploy Convex
|
||||
run: bun run convex:deploy
|
||||
|
||||
- name: Verify Convex contract
|
||||
run: bun run verify:convex-contract -- --prod
|
||||
|
||||
wait-vercel-production:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
needs:
|
||||
- preflight-secrets
|
||||
- deploy-convex
|
||||
steps:
|
||||
- name: Wait for Vercel production deployment
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||
GITHUB_SHA: ${{ github.sha }}
|
||||
VERCEL_STATUS_CONTEXT: Vercel – clawhub
|
||||
run: |
|
||||
for attempt in {1..90}; do
|
||||
state="$(gh api "repos/$GITHUB_REPOSITORY/commits/$GITHUB_SHA/status" \
|
||||
--jq '.statuses[] | select(.context == env.VERCEL_STATUS_CONTEXT) | .state' \
|
||||
2>/dev/null | head -n1)"
|
||||
|
||||
case "$state" in
|
||||
success)
|
||||
echo "Vercel production deployment ready for $GITHUB_SHA"
|
||||
exit 0
|
||||
;;
|
||||
failure|error)
|
||||
echo "::error::Vercel production deployment failed for $GITHUB_SHA"
|
||||
exit 1
|
||||
;;
|
||||
pending)
|
||||
echo "Vercel deployment pending for $GITHUB_SHA; waiting..."
|
||||
;;
|
||||
*)
|
||||
echo "Vercel status for $GITHUB_SHA not published yet; waiting..."
|
||||
;;
|
||||
esac
|
||||
|
||||
sleep 10
|
||||
done
|
||||
|
||||
echo "::error::Timed out waiting for Vercel production deployment for $GITHUB_SHA"
|
||||
exit 1
|
||||
|
||||
smoke-production:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
needs:
|
||||
- preflight-secrets
|
||||
- deploy-convex
|
||||
- wait-vercel-production
|
||||
env:
|
||||
PLAYWRIGHT_BASE_URL: https://clawhub.ai
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: oven-sh/setup-bun@e3914758a49697077f7bcd190d36582a61667aad
|
||||
with:
|
||||
bun-version: 1.3.10
|
||||
|
||||
- name: Install
|
||||
run: bun install --frozen-lockfile
|
||||
|
||||
- name: Install Playwright browser
|
||||
run: bunx playwright install --with-deps chromium
|
||||
|
||||
- name: Write authenticated storage state
|
||||
if: env.PLAYWRIGHT_AUTH_STORAGE_STATE_JSON != ''
|
||||
env:
|
||||
PLAYWRIGHT_AUTH_STORAGE_STATE_JSON: ${{ secrets.PLAYWRIGHT_AUTH_STORAGE_STATE_JSON }}
|
||||
run: |
|
||||
echo "$PLAYWRIGHT_AUTH_STORAGE_STATE_JSON" > "$RUNNER_TEMP/playwright-auth.json"
|
||||
echo "PLAYWRIGHT_AUTH_STORAGE_STATE=$RUNNER_TEMP/playwright-auth.json" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Smoke test production
|
||||
run: bunx playwright test e2e/menu-smoke.pw.test.ts e2e/upload-auth-smoke.pw.test.ts
|
||||
@@ -1,35 +0,0 @@
|
||||
name: "Security Gate: Secret Scanning"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main, master]
|
||||
|
||||
jobs:
|
||||
trufflehog:
|
||||
name: Scan for Verified Secrets
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read # Required to scan the code in the PR
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0 # necessary to support the scoping requirements below
|
||||
|
||||
- name: TruffleHog OSS
|
||||
id: trufflehog
|
||||
# Use a concrete released ref that resolves in upstream action registry.
|
||||
# v3 (major tag) is not published by trufflesecurity/trufflehog.
|
||||
uses: trufflesecurity/trufflehog@v3.93.8
|
||||
with:
|
||||
path: ./
|
||||
base: ${{ github.event.pull_request.base.sha }} # scope it to the committed files
|
||||
head: ${{ github.event.pull_request.head.sha }}
|
||||
extra_args: --only-verified --debug
|
||||
|
||||
- name: Notify on Failure
|
||||
if: steps.trufflehog.outcome == 'failure'
|
||||
run: |
|
||||
echo "::error::Verified secrets found! This PR contains live credentials that must be rotated immediately."
|
||||
echo "::notice::If these secrets are already in the commit history, they cannot be removed via a simple removal commit/push. A repository owner can contact GitHub Support to purge the cached data: https://support.github.com/contact/private-information"
|
||||
exit 1
|
||||
@@ -1,26 +0,0 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
.bun-build
|
||||
*.bun-build
|
||||
bin/docs-list
|
||||
dist
|
||||
dist-ssr
|
||||
!packages/schema/dist
|
||||
!packages/schema/dist/**
|
||||
*.local
|
||||
.vercel
|
||||
count.txt
|
||||
.env
|
||||
.nitro
|
||||
.tanstack
|
||||
.wrangler
|
||||
.output
|
||||
.vinxi
|
||||
todos.json
|
||||
.cta.json
|
||||
.vscode
|
||||
.env*.local
|
||||
coverage
|
||||
playwright-report
|
||||
test-results
|
||||
.playwright
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
||||
"experimentalSortImports": {
|
||||
"newlinesBetween": false,
|
||||
},
|
||||
"experimentalSortPackageJson": {
|
||||
"sortScripts": true,
|
||||
},
|
||||
"ignorePatterns": [
|
||||
".output/",
|
||||
".tanstack/",
|
||||
"convex/_generated/",
|
||||
"coverage/",
|
||||
"dist/",
|
||||
"node_modules/",
|
||||
"public/",
|
||||
"src/routeTree.gen.ts",
|
||||
"test-results/",
|
||||
],
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": ["unicorn", "typescript", "oxc"],
|
||||
"categories": {
|
||||
"correctness": "error",
|
||||
"perf": "error",
|
||||
"suspicious": "error"
|
||||
},
|
||||
"rules": {
|
||||
"curly": "off",
|
||||
"eslint-plugin-unicorn/prefer-array-find": "off",
|
||||
"eslint-plugin-unicorn/no-array-sort": "off",
|
||||
"eslint/no-await-in-loop": "off",
|
||||
"eslint/no-new": "off",
|
||||
"oxc/no-accumulating-spread": "off",
|
||||
"oxc/no-async-endpoint-handlers": "off",
|
||||
"oxc/no-map-spread": "off",
|
||||
"typescript/no-explicit-any": "error",
|
||||
"typescript/no-extraneous-class": "off",
|
||||
"typescript/no-unnecessary-boolean-literal-compare": "off",
|
||||
"typescript/no-unnecessary-type-assertion": "off",
|
||||
"typescript/no-unsafe-type-assertion": "off",
|
||||
"unicorn/consistent-function-scoping": "off",
|
||||
"unicorn/require-post-message-target-origin": "off"
|
||||
},
|
||||
"ignorePatterns": [
|
||||
".output/",
|
||||
".tanstack/",
|
||||
"convex/_generated/",
|
||||
"coverage/",
|
||||
"dist/",
|
||||
"node_modules/",
|
||||
"public/",
|
||||
"src/routeTree.gen.ts",
|
||||
"test-results/"
|
||||
]
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
# Repository Guidelines
|
||||
|
||||
## Project Structure & Module Organization
|
||||
|
||||
- `src/` — TanStack Start app code (routes, components, styles).
|
||||
- `convex/` — Convex backend (schema, queries/mutations/actions, HTTP routes).
|
||||
- `convex/_generated/` — generated Convex API/types; committed for builds.
|
||||
- `docs/` — product/spec docs (see `docs/spec.md`).
|
||||
- `public/` — static assets.
|
||||
|
||||
## Build, Test, and Development Commands
|
||||
|
||||
- `bun run dev` — local app server at `http://localhost:3000`.
|
||||
- `bun run build` — production build (Vite + Nitro).
|
||||
- `bun run preview` — preview built app.
|
||||
- `bunx convex dev` — Convex dev deployment + function watcher.
|
||||
- `bunx convex codegen` — regenerate `convex/_generated`.
|
||||
- `bun run lint` — Biome + oxlint (type-aware).
|
||||
- `bun run test` — Vitest (unit tests).
|
||||
- `bun run coverage` — coverage run; keep global >= 80%.
|
||||
|
||||
## Coding Style & Naming Conventions
|
||||
|
||||
- TypeScript strict; ESM.
|
||||
- Indentation: 2 spaces, single quotes (Biome).
|
||||
- Lint/format: Biome + oxlint (type-aware).
|
||||
- Convex function names: verb-first (`getBySlug`, `publishVersion`).
|
||||
|
||||
## Testing Guidelines
|
||||
|
||||
- Framework: Vitest 4 + jsdom.
|
||||
- Tests live in `src/**` and `convex/lib/**`.
|
||||
- Coverage threshold: 80% global (lines/functions/branches/statements).
|
||||
- Example: `convex/lib/skills.test.ts`.
|
||||
|
||||
## Commit & Pull Request Guidelines
|
||||
|
||||
- Commit messages: Conventional Commits (`feat:`, `fix:`, `chore:`, `docs:`…).
|
||||
- Keep changes scoped; avoid repo-wide search/replace.
|
||||
- PRs: include summary + test commands run. Add screenshots for UI changes.
|
||||
- Before merging any PR, verify TypeScript cleanly with `bunx tsc -p packages/schema/tsconfig.json --noEmit` and `bunx tsc -p packages/clawdhub/tsconfig.json --noEmit`; if Convex code changed, also run the repo typecheck path used by deploy so `bunx convex deploy` will not fail on `tsc`.
|
||||
- GitHub comments: for multiline `gh` comments/close messages, use `--body-file`, `--input`, or stdin/heredoc with real newlines; never pass literal `\\n` in shell strings.
|
||||
- Reject PRs that add skills into source code/repo content directly (for example under `skills/` or seed-only additions intended as published skills). Skills must be uploaded/published via CLI.
|
||||
|
||||
## Git Notes
|
||||
|
||||
- If `git branch -d/-D <branch>` is policy-blocked, delete the local ref directly: `git update-ref -d refs/heads/<branch>`.
|
||||
|
||||
## URL Quick Reference
|
||||
|
||||
- Canonical site: `https://clawhub.ai` (prefer this over legacy domains).
|
||||
- Skill page URL format: `https://clawhub.ai/<owner>/<slug>` (owner handle preferred; falls back to owner id).
|
||||
- Skill API detail URL: `https://clawhub.ai/api/v1/skills/<slug>`.
|
||||
- Skill file URL: `https://clawhub.ai/api/v1/skills/<slug>/file?path=SKILL.md`.
|
||||
- For “full URL?” requests, return the canonical page URL first, then API URL if useful.
|
||||
|
||||
## Configuration & Security
|
||||
|
||||
- Local env: `.env.local` (never commit secrets).
|
||||
- Convex env holds JWT keys; Vercel only needs `VITE_CONVEX_URL` + `VITE_CONVEX_SITE_URL`.
|
||||
- OAuth: GitHub OAuth App credentials required for login.
|
||||
|
||||
## Convex Ops (Gotchas)
|
||||
|
||||
- New Convex functions must be pushed before `convex run`: use `bunx convex dev --once` (dev) or `bunx convex deploy` (prod).
|
||||
- For non-interactive prod deploys, use `bunx convex deploy -y` to skip confirmation.
|
||||
- If `bunx convex run --env-file .env.local ...` returns `401 MissingAccessToken` despite `bunx convex login`, workaround: omit `--env-file` and use `--deployment-name <name>` / `--prod`.
|
||||
|
||||
## Convex Query & Bandwidth Rules
|
||||
|
||||
- **Always use `.withIndex()` instead of `.filter()` for fields that can be indexed.** `.filter()` causes full table scans — every doc is read and billed. Even a single `.filter()` on a 16K-row table reads ~16 MB per call.
|
||||
- **Convex reads entire documents** — no field projections. If you only need a few fields from large docs (~6 KB+), denormalize a lightweight summary onto the parent doc or use a lookup table (see `embeddingSkillMap`, `skill.latestVersionSummary`, `skill.badges` for examples).
|
||||
- **Denormalization pattern**: persist computed fields so they can be indexed. Every mutation that updates source fields must also update the denormalized field. Always write a cursor-based backfill for new fields (see `backfillIsSuspiciousInternal`, `backfillLatestVersionSummaryInternal`, `backfillDenormalizedBadgesInternal` for examples).
|
||||
- **Cron jobs must never scan entire tables.** Use indexed queries with equality filters. Use cursor-based pagination for large datasets. Prefer incremental/delta tracking over full recounts.
|
||||
- **32K document limit per query.** Split `.collect()` calls by a partition field (e.g., one day at a time instead of a 7-day range). See `rebuildTrendingLeaderboardAction` in `convex/leaderboards.ts` for an example.
|
||||
- **Common mistakes**: `.filter().collect()` without an index; `ctx.db.get()` on large docs in a loop for list views; while loops that paginate the whole table to find filtered results.
|
||||
- **Before writing or reviewing Convex queries, check deployment health.** Run `bunx convex insights` to check for OCC conflicts, `bytesReadLimit`, and `documentsReadLimit` errors. Run `bunx convex logs --failure` to see individual error messages and stack traces. This helps identify which functions are causing bandwidth issues so you can prioritize fixes.
|
||||
@@ -1,366 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
## 0.9.0 - 2026-03-23
|
||||
|
||||
### Added
|
||||
|
||||
- Packages/Plugins: add a first-class OpenClaw package registry across the web app, CLI, and HTTP API. ClawHub now supports package browse/search/detail/version/file/download flows plus `clawhub package explore`, `clawhub package inspect`, and `clawhub package publish` for `skill`, `code-plugin`, and `bundle-plugin` packages. (#1093)
|
||||
- Packages/Install: package downloads now ship install-ready archives with a `package/` root, support nested files like `dist/index.js`, and work directly with OpenClaw plugin install flows.
|
||||
- Skills/Web: server-render public skill pages and OG assets for faster first loads, cleaner sharing previews, and better cache behavior.
|
||||
|
||||
### Changed
|
||||
|
||||
- Browse/Search: rebuild public browse/search around denormalized digests, one-shot HTTP fetches, and deterministic cursors so the homepage and `/skills` are faster, more cacheable, and less likely to hit stale-tab or pagination dead ends.
|
||||
- Search: default skill search to relevance, keep load-more retryable after fetch failures, and tighten package/skill catalog query paths to reduce inconsistent results under load.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Packages/Auth: authenticated owners can now list, search, inspect, download, and read files from their own private packages instead of private packages being direct-URL-only. (#1093)
|
||||
- Packages/API: stabilize package latest-version pointers, cursor pagination, publish outputs, fallback release resolution, and app-origin auth handling so package publish/search/install flows stay reliable.
|
||||
- Visibility/API: prevent skills owned by deleted/banned users from showing up in public detail pages, browse/search results, or version API routes.
|
||||
- Skills/API: sanitize public skill and soul version/file reads so hidden or invalid version data does not leak through direct API access.
|
||||
- Skills/Web: keep Monaco compare layout toggles reliable while defaulting narrow screens to inline mode (#828) (thanks @geoffrey-xiao).
|
||||
|
||||
## 0.8.0 - 2026-03-13
|
||||
|
||||
### Added
|
||||
|
||||
- Skills/Web: show skill owner avatar + handle on skill cards, lists, and detail pages (#312) (thanks @ianalloway).
|
||||
- Skills/Web: add file viewer for skill version files on detail page (#44) (thanks @regenrek).
|
||||
- CLI: add `uninstall` command for skills (#241) (thanks @superlowburn).
|
||||
- Skills/API/CLI: add ownership transfer workflow with request/list/accept/reject/cancel flows.
|
||||
- Skills/Web/API: surface platform/architecture labels and security evaluation results in v1 + inspect views (#499, #362).
|
||||
- API: add structured skill moderation responses plus `GET /api/v1/skills/{slug}/moderation` with redacted public evidence and full owner/staff detail (#334) (thanks @ArthurzKV).
|
||||
- Moderation: persist structured moderation snapshots (static scan + VT/LLM merged verdict, reason codes, and evidence) on skills and versions (#333) (thanks @ArthurzKV).
|
||||
- API: add scan security verification endpoint and non-suspicious filters (#820).
|
||||
- Users: add `trustedPublisher` flag and admin mutations to bypass pending-scan auto-hide for trusted publishers (#298) (thanks @autogame-17).
|
||||
- Moderation: add comment reporting with per-user active report caps, unique reporter/target enforcement, and auto-hide on the 4th unique report.
|
||||
- Moderation: add AI-driven comment scam backfill (`commentModeration:*`) with persisted verdict/confidence/explainer metadata and strict auto-ban for `certain_scam` + `high` confidence.
|
||||
- Admin: add manual unban for banned users (clears `deletedAt` + `banReason`, audit log entry). Revoked API tokens stay revoked.
|
||||
- Admin: bulk restore skills from GitHub backup; reclaim squatted slugs via v1 endpoints + internal tooling (#298) (thanks @autogame-17).
|
||||
- Moderation/Admin: add manual override audit tools for suspicious-skill review.
|
||||
- CI/Security: add TruffleHog pull-request scanning for verified leaked credentials (#505) (thanks @akses0).
|
||||
|
||||
### Changed
|
||||
|
||||
- Skills: make published skill licensing explicit and fixed to MIT-0; require publish consent, surface no-attribution messaging in web/CLI/API, and remove per-skill license metadata.
|
||||
- Skill metadata: support env vars, dependency declarations, author, and links in parsed manifest metadata + install UI (#360) (thanks @mahsumaktas).
|
||||
- Rate limiting: apply authenticated quotas by user bucket (vs shared IP), emit delay-based reset headers, and improve CLI 429 guidance/retries (#412) (thanks @lc0rp).
|
||||
- Skills: reserve deleted slugs for prior owners (90-day cooldown) to prevent squatting; add admin reclaim flow (#298) (thanks @autogame-17).
|
||||
- Moderation: ban flow soft-deletes owned skills (reversible) and removes them from vector search (#298) (thanks @autogame-17).
|
||||
- Security/docs: document comment reporting/auto-hide behavior alongside existing skill reporting rules.
|
||||
- Security/moderation: add bounded explainable auto-ban reasons for scam comments and protect moderator/admin accounts from automated bans.
|
||||
- Moderation: banning users now also soft-deletes their authored comments (skill + soul), including legacy cleanup on re-ban.
|
||||
- Quality gate: language-aware word counting (`Intl.Segmenter`) and new `cjkChars` signal to reduce false rejects for non-Latin docs.
|
||||
- Jobs: run skill stat event processing every 5 minutes (was 15).
|
||||
- Deploy: add frontend/backend drift detection plus hardened production smoke/deploy checks.
|
||||
- API performance: batch resolve skill/soul tags in v1 list/get endpoints (fewer action->query round-trips) (#112) (thanks @mkrokosz).
|
||||
- LLM helpers: centralize OpenAI Responses text extraction for changelog/summary/eval flows (#502) (thanks @ianalloway).
|
||||
- Search/listing performance: cut embedding hydration and badge read bandwidth via `embeddingSkillMap` + denormalized skill badges; shift stat-doc sync to low-frequency cron (#441) (thanks @sethconvex).
|
||||
- Search/listing performance: move public browse/search hydration onto `skillSearchDigest`, add non-suspicious index paths, and split trending rebuilds to stay under Convex document limits.
|
||||
|
||||
### Fixed
|
||||
|
||||
- API: accept legacy CLI publish payloads during the v1 migration (#815).
|
||||
- Auth/UI: surface OAuth callback failures in the web UI instead of swallowing them (#688).
|
||||
- Skills: allow ownership healing when the previous owner was deleted/banned, and sanitize owner data in public payloads (#689, #793).
|
||||
- CLI: validate explicit `install --force --version` targets before removing an existing local skill, preventing data loss when the requested version does not exist (#825) (thanks @jonathandeamer).
|
||||
- Skills/Web: debounce search URL updates on `/skills` to keep typing responsive, and cancel stale pending navigations on external query changes (#587) (thanks @neeravmakwana).
|
||||
- Upload: keep folder-picking enabled after page refresh by reapplying `webkitdirectory`/`directory` on the file input ref (#551) (thanks @MunemHashmi).
|
||||
- CLI publish: use a longer multipart upload timeout and normalize abort rejections into proper Errors (#550) (thanks @MunemHashmi).
|
||||
- CLI: forward optional auth tokens for `search` and `explore` against authenticated registries (#608) (thanks @artdaal).
|
||||
- CLI: respect `HTTPS_PROXY`/`HTTP_PROXY`/`NO_PROXY` env vars for outbound registry requests, with troubleshooting docs (#363) (thanks @kerrypotter).
|
||||
- CLI: preserve registry base paths when composing API URLs for search/inspect/moderation commands (#486) (thanks @Liknox).
|
||||
- CLI: show manual URL guidance when automatic browser opening is unavailable; add regression tests for opener errors (#163) (thanks @aronchick).
|
||||
- API/CLI: expose skill security status in version inspect output, with schema wiring and CLI regression coverage (#362) (thanks @abutbul).
|
||||
- Moderation: remove over-broad keyword flags for common auth/payment/crypto terms so legitimate skills stop tripping regex prefilters (#273) (thanks @superlowburn).
|
||||
- Skills hard-delete: delete `commentReports` rows during moderation cleanup to avoid orphaned report records.
|
||||
- Comments: hide entries authored by deleted/deactivated users in `comments:listBySkill`.
|
||||
- Admin API: `POST /api/v1/users/reclaim` now performs non-destructive root-slug owner transfer
|
||||
(preserves existing skill versions/stats/metadata) and clears active slug reservations.
|
||||
- VirusTotal: use shared AV-engine fallback verdict mapping for pending/backfill flows and keep undetected-only results pending (#591) (thanks @Shuai-DaiDai).
|
||||
- Skills/listing: keep non-suspicious browse pagination on one cursor family during `isSuspicious` backfill, and re-sync stale `latestVersionSummary` metadata fields (#572) (thanks @sethconvex).
|
||||
- PWA: update `manifest.json` branding so installed apps show the correct ClawHub name (#569) (thanks @Glucksberg).
|
||||
- Search/tests: cover soft-deleted skill filtering in vector hydration and lexical exact-slug fallback (#552) (thanks @MunemHashmi).
|
||||
- Docs/dev: fix local setup instructions for Node support, Convex env vars, frontend port, and post-seed stats refresh (#584) (thanks @jack-piplabs).
|
||||
- Docs/CLI: fix `explore` flag list indentation so `--limit` renders correctly in the command reference (#601) (thanks @gandli).
|
||||
- Skill metadata: parse top-level `requires.*`, `primaryEnv`, and homepage fallbacks for security review accuracy (#548) (thanks @MunemHashmi).
|
||||
- Users: sync handle on ensure when GitHub login changes (#293) (thanks @christianhpoe).
|
||||
- Users/Auth: throttle GitHub profile sync on login; also sync avatar when it changes (#312) (thanks @ianalloway).
|
||||
- Upload gate: fetch GitHub account age by immutable account ID (prevents username swaps) (#116) (thanks @mkrokosz).
|
||||
- VT fallback: activate only VT-pending hidden skills when scans are unavailable/stale; keep quality/scanner-blocked skills hidden (#300) (thanks @superlowburn).
|
||||
- API: return proper status codes for delete/undelete errors (#35) (thanks @sergical).
|
||||
- API: for owners, return clearer status/messages for hidden/soft-deleted skills instead of a generic 404.
|
||||
- Web: allow copying OpenClaw scan summary text (thanks @borisolver, #322).
|
||||
- HTTP/CORS: add preflight handler + include CORS headers on API/download errors; CLI: include auth token for owner-visible installs/updates (#146) (thanks @Grenghis-Khan).
|
||||
- CLI: clarify `logout` only removes the local token; token remains valid until revoked in the web UI (#166) (thanks @aronchick).
|
||||
- CLI: validate skill slugs used for filesystem operations (prevents path traversal) (#241) (thanks @superlowburn).
|
||||
- Skills: keep global sorting across pagination on `/skills` (thanks @CodeBBakGoSu, #98).
|
||||
- Skills: allow updating skill description/summary from frontmatter on subsequent publishes (#312) (thanks @ianalloway).
|
||||
- Skills/Web: prevent filtered pagination dead-ends and loading-state flicker on `/skills`; move highlighted browse filtering into server list query (#339) (thanks @Marvae).
|
||||
- Web: align `/skills` total count with public visibility and format header count (thanks @rknoche6, #76).
|
||||
- Skills/Web: centralize public visibility checks and keep `globalStats` skill counts in sync incrementally; remove duplicate `/skills` default-sort fallback and share browse test mocks (thanks @rknoche6, #76).
|
||||
- Moderation: clear stale `flagged.suspicious` flags when VirusTotal rescans improve to clean verdicts (#418) (thanks @Phineas1500).
|
||||
- API tests: lock `Retry-After` behavior to relative-delay semantics for v1 search 429s (#421) (thanks @apoorvdarshan).
|
||||
- CLI tests: assert 5xx HTTP responses still perform retry attempts before surfacing final error (#457) (thanks @YonghaoZhao722).
|
||||
- GitHub import: improve storage/publish failure errors with actionable context; add regression tests for error formatting (#512) (thanks @vassiliylakhonin).
|
||||
|
||||
## 0.7.0 - 2026-02-16
|
||||
|
||||
Reconstructed from the `clawhub@0.7.0` npm publish timestamp (`2026-02-16T05:02:25Z`) and the repo version bump commit (`e352309`).
|
||||
|
||||
### Added
|
||||
|
||||
- Skills/Web: show owner avatars/handles across cards, lists, and detail pages (#312) (thanks @ianalloway).
|
||||
- Skills/Web: add version file viewer on skill detail pages (#44) (thanks @regenrek).
|
||||
- CLI: add `uninstall` for installed skills (#241) (thanks @superlowburn).
|
||||
- Skills/Web: add non-suspicious browse filter, downloads-first browse defaults, and popular non-suspicious homepage sections.
|
||||
- Web: compact-format skill and soul stats, plus split page models for skills/detail rendering.
|
||||
- Skills: auto-generate missing summaries and add a resumable/self-scheduling summary backfill job.
|
||||
- Moderation/Admin: add anti-spam publish caps, trust-tier quality checks, empty-skill cleanup tooling, and stronger moderator UX.
|
||||
|
||||
### Changed
|
||||
|
||||
- HTTP/CLI: centralize CORS handling and allow tokenized owner-visible reads through the CLI (#296, #297).
|
||||
- API performance: batch resolve tags in v1 list/get flows to cut action-to-query round-trips (#112) (thanks @mkrokosz).
|
||||
- Quality gate: add language-aware word counting and tighten spam/quarantine handling around publish flows.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Skills/Web: fix initial sort wiring, keep global ordering across pagination, prevent pagination dead-ends/flicker, and harden cursor recovery (#92, #98, #339).
|
||||
- CLI: normalize abort/timeout errors, secure config-file permissions, clarify logout semantics, and prefer `$HOME` for path resolution (#164, #166, #283, #286, #299).
|
||||
- API: return correct delete/undelete status codes and clearer soft-delete/owner-visible error responses (#35) (thanks @sergical).
|
||||
- Upload/Auth: gate publish ownership by immutable GitHub account ID and handle duplicate auth-user records safely.
|
||||
- Downloads/Search: harden download dedupe/rate limiting, improve SSR host awareness, and fix homepage/search regressions under legacy data.
|
||||
|
||||
## 0.6.1 - 2026-02-13
|
||||
|
||||
### Added
|
||||
|
||||
- Security: add LLM-based security evaluation during skill publish.
|
||||
- Parsing: recognize `metadata.openclaw` frontmatter and evaluate all skill files for requirements.
|
||||
|
||||
### Changed
|
||||
|
||||
- Performance: lazy-load Monaco diff viewer on demand (thanks @alexjcm, #212).
|
||||
- Search: improve recall/ranking with lexical fallback and relevance prioritization.
|
||||
- Moderation UX: collapse OpenClaw analysis by default; update spacing and default reasoning model.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Skills: fix initial `/skills` sort wiring so first page respects selected sort/direction (thanks @bpk9, #92).
|
||||
- Search/UI: add embedding request timeout and align `/skills` toolbar + list width (thanks @GhadiSaab, #53).
|
||||
- Upload gate: handle GitHub API rate limits and optional authenticated lookup token (thanks @superlowburn, #246).
|
||||
- HTTP: remove `allowH2` from Undici agent to prevent `fetch failed` on Node.js 22+ (#245).
|
||||
- Tests: add root `undici` dev dependency for Node E2E imports (thanks @tanujbhaud, #255).
|
||||
- Downloads: add download rate limiting + per-IP/day dedupe + scheduled dedupe pruning; preserve moderation gating and deterministic zips (thanks @regenrek, #43).
|
||||
- VirusTotal: fix scan sync race conditions and retry behavior in scan/backfill paths.
|
||||
- Metadata: tolerate trailing commas in JSON metadata.
|
||||
- Auth: allow soft-deleted users to re-authenticate on fresh login, while keeping banned users blocked (thanks @tanujbhaud, #177).
|
||||
- Web: prevent horizontal overflow from long code blocks in skill pages (thanks @bewithgaurav, #183).
|
||||
|
||||
## 0.6.0 - 2026-02-10
|
||||
|
||||
### Added
|
||||
|
||||
- CLI/API: add `set-role` to change user roles (admin only).
|
||||
- Security: quarantine skill publishes with VirusTotal scans + UI (thanks @aleph8, #130).
|
||||
- Testing: add tests for badges, skillZip, uploadFiles expandDroppedItems, and ark schema error truncation.
|
||||
- Moderation: add ban reasons to API/CLI and show in management UI.
|
||||
|
||||
### Changed
|
||||
|
||||
- Coverage: track `convex/lib/skillZip.ts` in coverage reports.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Web: show pending-scan skills to owners without 404 (thanks @orlyjamie, #136).
|
||||
- Users: backfill empty handles from name/email in ensure (thanks @adlai88, #158).
|
||||
- Web: update footer branding to OpenClaw (thanks @jontsai, #122).
|
||||
- Auth: restore soft-deleted users on reauth, block banned users (thanks @mkrokosz, #106).
|
||||
|
||||
## 0.5.0 - 2026-02-02
|
||||
|
||||
### Added
|
||||
|
||||
- Admin: ban users and delete owned skills from management console.
|
||||
- Moderation: auto-hide skills after 4 unique reports; per-user report cap; moderators can ban users.
|
||||
- Uploads: require GitHub accounts to be at least 7 days old for skill + soul publish/import.
|
||||
- CLI: add `inspect` to fetch skill metadata/files without installing.
|
||||
- CLI: add moderation commands for hide/unhide/delete and ban users.
|
||||
- Management: add filters for reported skills and users.
|
||||
|
||||
### Changed
|
||||
|
||||
- Deps: update dependencies to latest available versions.
|
||||
- Reporting: require reasons, show them in management console, warn about abuse bans.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Bans: batch hard-delete cleanup to avoid Convex read limits on large skills.
|
||||
|
||||
## 0.4.0 - 2026-01-30
|
||||
|
||||
### Added
|
||||
|
||||
- Web: show published skills on user profiles (thanks @njoylab, #20).
|
||||
- CLI: include ClawHub + Moltbot fallback skill roots for sync scans.
|
||||
- CLI: support OpenClaw configuration files (`OPENCLAW_CONFIG_PATH` / `OPENCLAW_STATE_DIR`).
|
||||
|
||||
### Changed
|
||||
|
||||
- Brand: rebrand to ClawHub and publish CLI as `clawhub` (legacy `clawdhub` supported).
|
||||
- Domain: default site/registry now `https://clawhub.ai`; `.well-known/clawhub.json` preferred.
|
||||
- Theme: persist theme under `clawhub-theme` (legacy key still read).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Registry: drop missing skills during search hydration (thanks @aaronn, #28).
|
||||
- CLI: use path-based skill metadata lookup for updates (thanks @daveonkels, #22).
|
||||
- Search: keep highlighted-only filtering and clamp vector candidates to Convex limits (thanks @aaronn, #30).
|
||||
|
||||
## 0.3.0 - 2026-01-19
|
||||
|
||||
### Added
|
||||
|
||||
- CLI: add `explore` command for latest updates, with limit clamping + tests/docs (thanks @jdrhyne, #14).
|
||||
- CLI: `explore --json` output + new sorts (`installs`, `installsAllTime`, `trending`) and limit up to 200.
|
||||
- API: `/api/v1/skills` supports installs + trending sorts (7-day installs).
|
||||
- API: idempotent `POST/DELETE /api/v1/stars/{slug}` endpoints.
|
||||
- Registry: trending leaderboard + daily stats backfill for installs-based sorts.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Web: keep search mode navigation and state in sync (thanks @NACC96, #12).
|
||||
|
||||
## 0.2.0 - 2026-01-13
|
||||
|
||||
### Added
|
||||
|
||||
- Web: dynamic OG image cards for skills (name, description, version).
|
||||
- CLI: auto-scan Clawdbot skill roots (per-agent workspaces, shared skills, extraDirs).
|
||||
- Web: import skills from public GitHub URLs (auto-detect `SKILL.md`, smart file selection, provenance).
|
||||
- Web/API: SoulHub (SOUL.md registry) with v1 endpoints and first-run auto-seed.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Web: stabilize skill OG image generation on server runtimes.
|
||||
- Web: prevent skill OG text overflow outside the card.
|
||||
- Registry: make SoulHub auto-seed idempotent and non-user-owned.
|
||||
- Registry: keep GitHub backup state + publish backups intact (thanks @joshp123, #1).
|
||||
- CLI/Registry: restore fork lineage on sync + clamp bulk list queries (thanks @joshp123, #1).
|
||||
- CLI: default workdir falls back to Clawdbot workspace (override with `--workdir` / `CLAWHUB_WORKDIR`).
|
||||
|
||||
## 0.0.6 - 2026-01-07
|
||||
|
||||
### Added
|
||||
|
||||
- API: v1 public REST endpoints with rate limits, raw file fetch, and OpenAPI spec.
|
||||
- Docs: `docs/api.md` and `DEPRECATIONS.md` for the v1 cutover plan.
|
||||
|
||||
### Changed
|
||||
|
||||
- CLI: publish now uses single multipart `POST /api/v1/skills`.
|
||||
- Registry: legacy `/api/*` + `/api/cli/*` marked for deprecation (kept for now).
|
||||
|
||||
## 0.0.5 - 2026-01-06
|
||||
|
||||
### Added
|
||||
|
||||
- Telemetry: track installs via `clawhub sync` (logged-in only), per root, with 120-day staleness.
|
||||
- Skills: show current + all-time installs; sort by installs.
|
||||
- Profile: private "Installed" tab with JSON export + delete telemetry controls.
|
||||
- Docs: add `docs/telemetry.md` (what we track + how to opt out).
|
||||
- Web: custom Open Graph image (`/og.png`) + richer OG/Twitter tags.
|
||||
- Web: dashboard for managing your published skills (thanks @dbhurley!).
|
||||
|
||||
### Changed
|
||||
|
||||
- CLI: telemetry opt-out via `CLAWHUB_DISABLE_TELEMETRY=1`.
|
||||
- Web: move theme picker into mobile menu.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Web: handle shorthand hex colors in diff theme (thanks @dbhurley!).
|
||||
|
||||
## 0.0.5 - 2026-01-06
|
||||
|
||||
### Added
|
||||
|
||||
- Maintenance: admin backfill to re-parse `SKILL.md` and repair stored summaries/parsed metadata.
|
||||
|
||||
### Fixed
|
||||
|
||||
- CLI sync: ignore plural `skills.md` docs files when scanning for skills.
|
||||
- Registry: parse YAML frontmatter (incl multiline `description`) and accept YAML `metadata` objects.
|
||||
|
||||
## 0.0.4 - 2026-01-05
|
||||
|
||||
### Added
|
||||
|
||||
- Web: `/skills` list view with sorting (newest/downloads/stars/name) + quick filter.
|
||||
- Web: admin/moderator highlight toggle on skill detail.
|
||||
- Web: canonical skill URLs as `/<owner>/<slug>` (legacy `/skills/<slug>` redirects).
|
||||
- Web: upload auto-generates a changelog via OpenAI when left blank (marked as auto-generated).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Web: skill detail shows a loading state instead of flashing "Skill not found".
|
||||
- Web: user profile shows avatar + loading state (no "User not found" flash).
|
||||
- Web: improved mobile responsiveness (nav menu, skill detail layout, install command overflow).
|
||||
- Web: upload now unwraps folder picks so `SKILL.md` can be at the bundle root.
|
||||
- Registry: cap embedding payload size to avoid model context errors.
|
||||
- CLI: ignore legacy `auth.clawdhub.com` registry and prefer site discovery.
|
||||
|
||||
### Changed
|
||||
|
||||
- Web: homepage search now expands into full search mode with live results + highlighted toggle.
|
||||
- CLI: sync no longer prompts for changelog; registry auto-generates when blank.
|
||||
|
||||
## 0.0.3 - 2026-01-04
|
||||
|
||||
### Added
|
||||
|
||||
- CLI sync: concurrency flag to limit registry checks.
|
||||
- Home: install command switcher (npm/pnpm/bun).
|
||||
|
||||
### Changed
|
||||
|
||||
- CLI sync: default `--concurrency` is now 4 (was 8).
|
||||
- CLI sync: replace boxed notes with plain output for long lists.
|
||||
|
||||
### Fixed
|
||||
|
||||
- CLI sync: wrap note output to avoid terminal overflow; cap list lengths.
|
||||
- CLI sync: label fallback scans as fallback locations.
|
||||
- CLI package: bundle schema internally (no external `clawhub-schema` publish).
|
||||
- Repo: mark `clawhub-schema` as private to prevent publishing.
|
||||
|
||||
## 0.0.2 - 2026-01-04
|
||||
|
||||
### Added
|
||||
|
||||
- CLI: delete/undelete commands for soft-deleted skills (owner/admin).
|
||||
|
||||
### Fixed
|
||||
|
||||
- CLI sync: dedupe duplicate slugs across scan roots; skip duplicates to avoid double-publish errors.
|
||||
- CLI sync: show parsing progress while hashing local skills.
|
||||
- CLI sync: prompt only actionable skills; preselect all by default; list synced separately; condensed synced summary when nothing to sync.
|
||||
- CLI sync: cap long status lists to avoid massive terminal boxes.
|
||||
- CLI publish/sync: allow empty changelog on updates; registry accepts empty changelog for updates.
|
||||
- CLI: use `--cli-version` to avoid conflict with skill `--version` flags.
|
||||
- Registry: hide soft-deleted skills from search/skill/download unless restored.
|
||||
- Tests: add delete/undelete coverage (unit + e2e).
|
||||
|
||||
## 0.0.1 - 2026-01-04
|
||||
|
||||
### Features
|
||||
|
||||
- CLI auth: login/logout/whoami; browser loopback auth; token storage; site/registry discovery; config overrides.
|
||||
- CLI workflow: search, install, update (single/all), list, publish, sync (scan workdir + legacy roots), dry-run, version bumping, tags.
|
||||
- Registry/API: skills + versions with semver; tags (latest + custom); changelog per version; SKILL.md frontmatter parsing; text-only validation; zip download; hash resolve; stats (downloads/stars/versions/comments).
|
||||
- Web app: home (highlighted + latest), search, skill detail (README, versions, tags, stats, files), upload UI, user profiles, stars, settings (profile + API tokens + delete account).
|
||||
- Social: stars + comments with moderation hooks; admin console for roles + highlighted curation.
|
||||
- Search: semantic/vector search over skill content with limit/approved filters.
|
||||
- Security: GitHub OAuth; role-based access (admin/moderator/user); audit logging for admin actions.
|
||||
@@ -1,36 +0,0 @@
|
||||
# ClawHub — Project Rules
|
||||
|
||||
## Convex Performance Rules
|
||||
|
||||
- For public listing/browse pages, use `ConvexHttpClient.query()` (one-shot fetch),
|
||||
not `useQuery`/`usePaginatedQuery` (reactive subscription). Reserve reactive
|
||||
queries for data the user needs to see update in real time.
|
||||
- Denormalize hot read paths into a single lightweight "digest" table. Every
|
||||
`ctx.db.get()` join adds a table to the reactive invalidation scope.
|
||||
- When a `skillSearchDigest` row is available, use `digestToOwnerInfo(digest)`
|
||||
to resolve owner data. NEVER call `ctx.db.get(ownerUserId)` when digest
|
||||
owner fields (`ownerHandle`, `ownerName`, `ownerDisplayName`, `ownerImage`)
|
||||
are already present. Reading from `users` adds the entire table to the
|
||||
reactive read set and wastes bandwidth.
|
||||
- Use `convex-helpers` Triggers to sync denormalized tables automatically.
|
||||
Always add change detection — skip the write if no fields actually changed.
|
||||
- Use compound indexes instead of JS filtering. If you're filtering docs after
|
||||
the query, you're scanning documents you'll throw away.
|
||||
- For search results scored by computed values (vector + lexical + popularity),
|
||||
fetch all results once and paginate client-side. Don't re-run the full search
|
||||
pipeline on "load more."
|
||||
- Backfills on reactively-subscribed tables need `delayMs` between batches.
|
||||
- Mutations that read >8 MB should use the Action → Query → Mutation pattern
|
||||
to split reads across transactions.
|
||||
|
||||
## Convex Conventions
|
||||
|
||||
- All mutations import from `convex/functions.ts` (not `convex/_generated/server`)
|
||||
to get trigger wrapping. Type imports still come from `convex/_generated/server`.
|
||||
- NEVER use `--typecheck=disable` on `npx convex deploy`.
|
||||
- Use `npx convex dev --once` to push functions once (not long-running watcher).
|
||||
|
||||
## Testing
|
||||
|
||||
- Tests use `._handler` to call mutation handlers directly with mock `db` objects.
|
||||
- Mock `db` objects MUST include `normalizeId: vi.fn()` for trigger wrapper compatibility.
|
||||
@@ -1,180 +0,0 @@
|
||||
# Contributing to ClawHub
|
||||
|
||||
Welcome! ClawHub is the public skill registry for [OpenClaw](https://github.com/openclaw/openclaw). We appreciate bug fixes, documentation improvements, and feature contributions.
|
||||
|
||||
- **Questions?** Ask in [#clawhub on Discord](https://discord.gg/clawd).
|
||||
- **Bug fixes** — PRs are welcome.
|
||||
- **New features or architectural changes** — please start with a Discord conversation in #clawhub first so we can align on scope.
|
||||
|
||||
## Local Development Setup
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- [Bun](https://bun.sh/) (Convex CLI runs via `bunx`, no global install needed)
|
||||
- [Node.js](https://nodejs.org/) v18, 20, 22, or 24 (required by the local Convex backend; v25+ is not yet supported)
|
||||
|
||||
### Install and configure
|
||||
|
||||
```bash
|
||||
bun install
|
||||
cp .env.local.example .env.local
|
||||
```
|
||||
|
||||
Edit `.env.local` with the following values for **local Convex**:
|
||||
|
||||
```bash
|
||||
# Frontend
|
||||
VITE_CONVEX_URL=http://127.0.0.1:3210
|
||||
VITE_CONVEX_SITE_URL=http://127.0.0.1:3210
|
||||
SITE_URL=http://localhost:3000
|
||||
|
||||
# Deployment used by `bunx convex dev`
|
||||
CONVEX_DEPLOYMENT=anonymous:anonymous-clawhub
|
||||
```
|
||||
|
||||
### GitHub OAuth App (for login)
|
||||
|
||||
1. Go to [github.com/settings/developers](https://github.com/settings/developers) and create a new OAuth App.
|
||||
2. Set **Homepage URL** to `http://localhost:3000`.
|
||||
3. Set **Authorization callback URL** to `http://127.0.0.1:3210/api/auth/callback/github`.
|
||||
4. Copy the Client ID and generate a Client Secret.
|
||||
|
||||
### Run the Convex backend
|
||||
|
||||
Start the local Convex backend first — other setup steps depend on it:
|
||||
|
||||
```bash
|
||||
bunx convex dev --typecheck=disable
|
||||
```
|
||||
|
||||
### Set backend environment variables
|
||||
|
||||
The Convex backend has its own env var store separate from `.env.local`. With the backend running, open a new terminal and set the required variables:
|
||||
|
||||
```bash
|
||||
bunx convex env set AUTH_GITHUB_ID <your-client-id>
|
||||
bunx convex env set AUTH_GITHUB_SECRET <your-client-secret>
|
||||
bunx convex env set SITE_URL http://localhost:3000
|
||||
```
|
||||
|
||||
### JWT keys (for Convex Auth)
|
||||
|
||||
With the backend still running, generate the signing keys:
|
||||
|
||||
```bash
|
||||
bunx @convex-dev/auth
|
||||
```
|
||||
|
||||
This sets `JWT_PRIVATE_KEY` and `JWKS` on the Convex backend and outputs values you can also save to `.env.local` for reference.
|
||||
|
||||
### Run the frontend
|
||||
|
||||
```bash
|
||||
bun run dev -- --port 3000
|
||||
```
|
||||
|
||||
Change the port if 3000 is already in use, and update `SITE_URL` in both `.env.local` and the Convex backend (`bunx convex env set SITE_URL ...`) to match.
|
||||
|
||||
### Seed the database
|
||||
|
||||
Populate sample data so the UI isn't empty:
|
||||
|
||||
```bash
|
||||
# 3 sample skills (padel, gohome, xuezh)
|
||||
bunx convex run --no-push devSeed:seedNixSkills
|
||||
|
||||
# 50 extra skills for pagination testing (optional)
|
||||
bunx convex run --no-push devSeedExtra:seedExtraSkillsInternal
|
||||
|
||||
# Refresh the cached skills count (required after seeding)
|
||||
bunx convex run --no-push statsMaintenance:updateGlobalStatsInternal
|
||||
```
|
||||
|
||||
To reset and re-seed:
|
||||
|
||||
```bash
|
||||
bunx convex run --no-push devSeed:seedNixSkills '{"reset": true}'
|
||||
```
|
||||
|
||||
### Optional environment variables
|
||||
|
||||
These features degrade gracefully without their keys:
|
||||
|
||||
| Variable | Purpose |
|
||||
| ------------------------------------------------------------------------- | --------------------------------------------------------- |
|
||||
| `OPENAI_API_KEY` | Embeddings and vector search (falls back to zero vectors) |
|
||||
| `VT_API_KEY` | VirusTotal malware scanning |
|
||||
| `DISCORD_WEBHOOK_URL` | Discord notifications |
|
||||
| `GITHUB_APP_ID` / `GITHUB_APP_PRIVATE_KEY` / `GITHUB_APP_INSTALLATION_ID` | GitHub backup sync |
|
||||
|
||||
## CLI Development
|
||||
|
||||
The CLI source lives in [`packages/clawdhub/`](packages/clawdhub/). Both `clawhub` and `clawdhub` are registered as bin aliases.
|
||||
|
||||
To test the CLI against your local instance:
|
||||
|
||||
```bash
|
||||
CLAWHUB_REGISTRY=http://127.0.0.1:3210 CLAWHUB_SITE=http://localhost:3000 clawhub search "padel"
|
||||
```
|
||||
|
||||
Manual smoke tests are documented in [`docs/manual-testing.md`](docs/manual-testing.md).
|
||||
|
||||
## Skill & Soul Publishing
|
||||
|
||||
- Skill format reference: [`docs/skill-format.md`](docs/skill-format.md)
|
||||
- Soul format reference: [`docs/soul-format.md`](docs/soul-format.md)
|
||||
- End-to-end walkthrough (search, install, publish, sync): [`docs/quickstart.md`](docs/quickstart.md)
|
||||
|
||||
Quick publish:
|
||||
|
||||
```bash
|
||||
clawhub publish <path-to-skill-directory>
|
||||
```
|
||||
|
||||
## Before Submitting a PR
|
||||
|
||||
```bash
|
||||
bun run lint # oxlint
|
||||
bun run test # Vitest (80% coverage threshold)
|
||||
bun run build # Vite + Nitro
|
||||
```
|
||||
|
||||
These are the same checks that run in CI (`.github/workflows/ci.yml`).
|
||||
|
||||
**PR guidelines:**
|
||||
|
||||
- Keep PRs focused — one concern per PR.
|
||||
- Use [Conventional Commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `chore:`, `docs:`, etc.
|
||||
- Include test commands and screenshots for UI changes.
|
||||
- Write a clear description of what changed and why.
|
||||
|
||||
## AI-Generated Code
|
||||
|
||||
AI-assisted contributions are welcome. When submitting AI-generated or AI-assisted code:
|
||||
|
||||
- Note it in the PR description.
|
||||
- Describe the level of testing you applied.
|
||||
- Include prompts if useful for reviewers.
|
||||
- Confirm that you understand and can maintain the code.
|
||||
|
||||
## Security Reporting
|
||||
|
||||
Report vulnerabilities to **security@openclaw.ai** with:
|
||||
|
||||
- Severity assessment
|
||||
- Technical reproduction steps
|
||||
- Suggested remediation
|
||||
|
||||
See [`docs/security.md`](docs/security.md) for moderation and upload gating details.
|
||||
|
||||
## Reading Order for New Contributors
|
||||
|
||||
1. This file (local setup)
|
||||
2. [`docs/quickstart.md`](docs/quickstart.md) — end-to-end workflows
|
||||
3. [`docs/architecture.md`](docs/architecture.md) — system design
|
||||
4. [`docs/skill-format.md`](docs/skill-format.md) — skill structure
|
||||
5. [`docs/cli.md`](docs/cli.md) — CLI reference
|
||||
6. [`docs/http-api.md`](docs/http-api.md) — HTTP endpoints
|
||||
7. [`docs/auth.md`](docs/auth.md) — authentication
|
||||
8. [`docs/deploy.md`](docs/deploy.md) — deployment
|
||||
9. [`docs/troubleshooting.md`](docs/troubleshooting.md) — common issues
|
||||
@@ -1,7 +0,0 @@
|
||||
# Deprecations
|
||||
|
||||
## Legacy /api routes (pre-v1)
|
||||
|
||||
- Deprecated: 2026-01-07
|
||||
- TODO: remove legacy `/api/*` and `/api/cli/*` routes after clients migrate to `/api/v1`.
|
||||
- Legacy handlers live in `convex/http.ts` and `convex/httpApi.ts`.
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Peter Steinberger
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,230 +0,0 @@
|
||||
<p align="center">
|
||||
<img src="public/clawd-logo.png" alt="ClawHub" width="120">
|
||||
</p>
|
||||
|
||||
<h1 align="center">ClawHub</h1>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/openclaw/clawhub/actions/workflows/ci.yml?branch=main"><img src="https://img.shields.io/github/actions/workflow/status/openclaw/clawhub/ci.yml?branch=main&style=for-the-badge" alt="CI status"></a>
|
||||
<a href="https://discord.gg/clawd"><img src="https://img.shields.io/discord/1456350064065904867?label=Discord&logo=discord&logoColor=white&color=5865F2&style=for-the-badge" alt="Discord"></a>
|
||||
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg?style=for-the-badge" alt="MIT License"></a>
|
||||
</p>
|
||||
|
||||
ClawHub is the **public skill registry for Clawdbot**: publish, version, and search text-based agent skills (a `SKILL.md` plus supporting files).
|
||||
It's designed for fast browsing + a CLI-friendly API, with moderation hooks and vector search.
|
||||
It also now exposes a native **OpenClaw package catalog** for code plugins and bundle plugins.
|
||||
|
||||
onlycrabs.ai is the **SOUL.md registry**: publish and share system lore the same way you publish skills.
|
||||
|
||||
<p align="center">
|
||||
<a href="https://clawhub.ai">ClawHub</a> ·
|
||||
<a href="https://onlycrabs.ai">onlycrabs.ai</a> ·
|
||||
<a href="VISION.md">Vision</a> ·
|
||||
<a href="docs/README.md">Docs</a> ·
|
||||
<a href="CONTRIBUTING.md">Contributing</a> ·
|
||||
<a href="https://discord.gg/clawd">Discord</a>
|
||||
</p>
|
||||
|
||||
## What you can do with it
|
||||
|
||||
- Browse skills + render their `SKILL.md`.
|
||||
- Publish new skill versions with changelogs + tags (including `latest`).
|
||||
- Rename an owned skill without breaking old links or installs.
|
||||
- Merge duplicate owned skills into one canonical slug.
|
||||
- Browse souls + render their `SOUL.md`.
|
||||
- Publish new soul versions with changelogs + tags.
|
||||
- Search via embeddings (vector index) instead of brittle keywords.
|
||||
- Star + comment; admins/mods can curate and approve skills.
|
||||
- Browse OpenClaw packages with family/trust/capability metadata.
|
||||
- Publish native code plugins and bundle plugins through `/packages` APIs and CLI flows.
|
||||
|
||||
## onlycrabs.ai (SOUL.md registry)
|
||||
|
||||
- Entry point is host-based: `onlycrabs.ai`.
|
||||
- On the onlycrabs.ai host, the home page and nav default to souls.
|
||||
- On ClawHub, souls live under `/souls`.
|
||||
- Soul bundles only accept `SOUL.md` for now (no extra files).
|
||||
|
||||
## How it works (high level)
|
||||
|
||||
- Web app: TanStack Start (React, Vite/Nitro).
|
||||
- Backend: Convex (DB + file storage + HTTP actions) + Convex Auth (GitHub OAuth).
|
||||
- Search: OpenAI embeddings (`text-embedding-3-small`) + Convex vector search.
|
||||
- API schema + routes: `packages/schema` (`clawhub-schema`).
|
||||
|
||||
## CLI
|
||||
|
||||
Common CLI flows:
|
||||
|
||||
- Auth: `clawhub login`, `clawhub whoami`
|
||||
- Discover: `clawhub search ...`, `clawhub explore`
|
||||
- Browse unified catalog (skills + plugins): `clawhub package explore`, `clawhub package inspect <name>`
|
||||
- Manage local installs: `clawhub install <slug>`, `clawhub uninstall <slug>`, `clawhub list`, `clawhub update --all`
|
||||
- Inspect without installing: `clawhub inspect <slug>`
|
||||
- Publish/sync: `clawhub publish <path>`, `clawhub sync`
|
||||
- Publish plugins: `clawhub package publish <path> [--owner <handle>] --source-repo <owner/repo> --source-commit <sha>`
|
||||
- Canonicalize owned skills: `clawhub skill rename <slug> <new-slug>`, `clawhub skill merge <source> <target>`
|
||||
|
||||
Docs: [`docs/quickstart.md`](docs/quickstart.md), [`docs/cli.md`](docs/cli.md).
|
||||
|
||||
### Removal permissions
|
||||
|
||||
- `clawhub uninstall <slug>` only removes a local install on your machine.
|
||||
- Uploaded registry skills use soft-delete/restore (`clawhub delete <slug>` / `clawhub undelete <slug>` or API equivalents).
|
||||
- Soft-delete/restore is allowed for the skill owner, moderators, and admins.
|
||||
- Hard delete is admin-only (management tools / ban flows).
|
||||
- Owner rename keeps the old slug as a redirect alias.
|
||||
- Owner merge hides the source listing and redirects the old slug to the canonical target.
|
||||
|
||||
## Telemetry
|
||||
|
||||
ClawHub tracks minimal **install telemetry** (to compute install counts) when you run `clawhub sync` while logged in.
|
||||
Disable via:
|
||||
|
||||
```bash
|
||||
export CLAWHUB_DISABLE_TELEMETRY=1
|
||||
```
|
||||
|
||||
Details: [`docs/telemetry.md`](docs/telemetry.md).
|
||||
|
||||
## Repo layout
|
||||
|
||||
- `src/` — TanStack Start app (routes, components, styles).
|
||||
- `convex/` — schema + queries/mutations/actions + HTTP API routes.
|
||||
- `packages/schema/` — shared API types/routes for the CLI and app.
|
||||
- [`docs/`](docs/README.md) — project documentation (architecture, CLI, auth, deployment, and more).
|
||||
- [`docs/spec.md`](docs/spec.md) — product + implementation spec (good first read).
|
||||
|
||||
## Local dev
|
||||
|
||||
Prereqs: [Bun](https://bun.sh/) (Convex runs via `bunx`, no global install needed).
|
||||
|
||||
```bash
|
||||
bun install
|
||||
cp .env.local.example .env.local
|
||||
# edit .env.local — see CONTRIBUTING.md for local Convex values
|
||||
|
||||
# terminal A: local Convex backend
|
||||
bunx convex dev
|
||||
|
||||
# terminal B: web app (port 3000)
|
||||
bun run dev
|
||||
|
||||
# seed sample data
|
||||
bunx convex run --no-push devSeed:seedNixSkills
|
||||
```
|
||||
|
||||
For full setup instructions (env vars, GitHub OAuth, JWT keys, database seeding), see [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
## Environment
|
||||
|
||||
- `VITE_CONVEX_URL`: Convex deployment URL (`https://<deployment>.convex.cloud`).
|
||||
- `VITE_CONVEX_SITE_URL`: Convex site URL (`https://<deployment>.convex.site`).
|
||||
- `VITE_SOULHUB_SITE_URL`: onlycrabs.ai site URL (`https://onlycrabs.ai`).
|
||||
- `VITE_SOULHUB_HOST`: onlycrabs.ai host match (`onlycrabs.ai`).
|
||||
- `VITE_SITE_MODE`: Optional override (`skills` or `souls`) for SSR builds.
|
||||
- `CONVEX_SITE_URL`: same as `VITE_CONVEX_SITE_URL` (auth + cookies).
|
||||
- `SITE_URL`: App URL (local: `http://localhost:3000`).
|
||||
- `AUTH_GITHUB_ID` / `AUTH_GITHUB_SECRET`: GitHub OAuth App.
|
||||
- `JWT_PRIVATE_KEY` / `JWKS`: Convex Auth keys.
|
||||
- `OPENAI_API_KEY`: embeddings for search + indexing.
|
||||
|
||||
## Nix plugins (nixmode skills)
|
||||
|
||||
ClawHub can store a nix-clawdbot plugin pointer in SKILL frontmatter so the registry knows which
|
||||
Nix package bundle to install. A nix plugin is different from a regular skill pack: it bundles the
|
||||
skill pack, the CLI binary, and its config flags/requirements together.
|
||||
|
||||
Add this to `SKILL.md`:
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: peekaboo
|
||||
description: Capture and automate macOS UI with the Peekaboo CLI.
|
||||
metadata:
|
||||
{
|
||||
"clawdbot":
|
||||
{
|
||||
"nix":
|
||||
{
|
||||
"plugin": "github:clawdbot/nix-steipete-tools?dir=tools/peekaboo",
|
||||
"systems": ["aarch64-darwin"],
|
||||
},
|
||||
},
|
||||
}
|
||||
---
|
||||
```
|
||||
|
||||
Install via nix-clawdbot:
|
||||
|
||||
```nix
|
||||
programs.clawdbot.plugins = [
|
||||
{ source = "github:clawdbot/nix-steipete-tools?dir=tools/peekaboo"; }
|
||||
];
|
||||
```
|
||||
|
||||
You can also declare config requirements + an example snippet:
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: padel
|
||||
description: Check padel court availability and manage bookings via Playtomic.
|
||||
metadata:
|
||||
{
|
||||
"clawdbot":
|
||||
{
|
||||
"config":
|
||||
{
|
||||
"requiredEnv": ["PADEL_AUTH_FILE"],
|
||||
"stateDirs": [".config/padel"],
|
||||
"example": "config = { env = { PADEL_AUTH_FILE = \\\"/run/agenix/padel-auth\\\"; }; };",
|
||||
},
|
||||
},
|
||||
}
|
||||
---
|
||||
```
|
||||
|
||||
To show CLI help (recommended for nix plugins), include the `cli --help` output:
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: padel
|
||||
description: Check padel court availability and manage bookings via Playtomic.
|
||||
metadata: { "clawdbot": { "cliHelp": "padel --help\\nUsage: padel [command]\\n" } }
|
||||
---
|
||||
```
|
||||
|
||||
`metadata.clawdbot` is preferred, but `metadata.clawdis` and `metadata.openclaw` are accepted as aliases.
|
||||
|
||||
## Skill metadata
|
||||
|
||||
Skills declare their runtime requirements (env vars, binaries, install specs) in the `SKILL.md` frontmatter. ClawHub's security analysis checks these declarations against actual skill behavior.
|
||||
|
||||
Full reference: [`docs/skill-format.md`](docs/skill-format.md#frontmatter-metadata)
|
||||
|
||||
Quick example:
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: my-skill
|
||||
description: Does a thing with an API.
|
||||
metadata:
|
||||
openclaw:
|
||||
requires:
|
||||
env:
|
||||
- MY_API_KEY
|
||||
bins:
|
||||
- curl
|
||||
primaryEnv: MY_API_KEY
|
||||
---
|
||||
```
|
||||
|
||||
## Scripts
|
||||
|
||||
```bash
|
||||
bun run dev
|
||||
bun run build
|
||||
bun run test
|
||||
bun run coverage
|
||||
bun run lint
|
||||
```
|
||||
@@ -1,98 +0,0 @@
|
||||
## OpenClaw Vision
|
||||
|
||||
OpenClaw is the AI that actually does things.
|
||||
It runs on your devices, in your channels, with your rules.
|
||||
|
||||
This document explains the current state and direction of the project.
|
||||
We are still early, so iteration is fast.
|
||||
Project overview and developer docs: [`README.md`](README.md)
|
||||
|
||||
OpenClaw started as my personal playground to learn AI and build something genuinely useful:
|
||||
an assistant that can run real tasks on my computer.
|
||||
It evolved through several names and shells: Warelay -> Clawdbot -> Moltbot -> OpenClaw.
|
||||
|
||||
The goal? A personal assistant that's easy to use, supports a wide range of platforms, and respects your privacy and security.
|
||||
|
||||
The current focus is:
|
||||
|
||||
Priority:
|
||||
|
||||
- Security and safe defaults
|
||||
- Bug fixes and stability
|
||||
- Setup reliability and first-run UX
|
||||
|
||||
Next priorities:
|
||||
|
||||
- Supporting all major model providers
|
||||
- Improving support for major messaging channels (and adding a few high-demand ones)
|
||||
- Performance and test infrastructure
|
||||
- Better computer-use and agent harness capabilities
|
||||
- Ergonomics across CLI and web frontend
|
||||
- Companion apps on macOS, iOS, Android, Windows, and Linux
|
||||
|
||||
## Security
|
||||
|
||||
Security in OpenClaw is a deliberate tradeoff: strong defaults without killing capability.
|
||||
The goal is to stay powerful for real work while making risky paths explicit and operator-controlled.
|
||||
|
||||
Canonical security policy and reporting:
|
||||
|
||||
- https://github.com/openclaw/openclaw/blob/main/SECURITY.md
|
||||
|
||||
We prioritize secure defaults, but we also expose clear knobs for trusted high-power workflows.
|
||||
|
||||
## Plugins & Memory
|
||||
|
||||
OpenClaw has an extensive plugin API.
|
||||
Core stays lean; optional capability should usually ship as plugins.
|
||||
|
||||
Preferred plugin path is npm package distribution plus local extension loading for development.
|
||||
If you build a plugin, please host and maintain it in your own repository.
|
||||
The bar for adding optional plugins to core is intentionally high.
|
||||
|
||||
Memory is a special plugin slot where only one memory plugin can be active at a time.
|
||||
Today we ship multiple memory options; over time we plan to converge on one recommended default path.
|
||||
|
||||
### Skills
|
||||
|
||||
We still ship some bundled skills for baseline UX.
|
||||
New skills should be published to ClawHub first (`clawhub.ai`), not added to core by default.
|
||||
Core skill additions should be rare and require a strong product or security reason.
|
||||
|
||||
### MCP Support
|
||||
|
||||
OpenClaw supports MCP through `mcporter`: https://github.com/steipete/mcporter
|
||||
|
||||
This keeps MCP integration flexible and decoupled from core runtime:
|
||||
|
||||
- add or change MCP servers without restarting the gateway
|
||||
- keep core tool/context surface lean
|
||||
- reduce MCP churn impact on core stability and security
|
||||
|
||||
For now, we prefer this bridge model over building first-class MCP runtime into core.
|
||||
If there is an MCP server or feature `mcporter` does not support yet, please open an issue there.
|
||||
|
||||
### Setup
|
||||
|
||||
OpenClaw is currently terminal-first by design.
|
||||
This keeps setup explicit: users see docs, auth, permissions, and security posture up front.
|
||||
|
||||
Long term, we want easier onboarding flows as hardening matures.
|
||||
We do not want convenience wrappers that hide critical security decisions from users.
|
||||
|
||||
### Why TypeScript?
|
||||
|
||||
OpenClaw is primarily an orchestration system: prompts, tools, protocols, and integrations.
|
||||
TypeScript was chosen to keep OpenClaw hackable by default.
|
||||
It is widely known, fast to iterate in, and easy to read, modify, and extend.
|
||||
|
||||
## What We Will Not Merge (For Now)
|
||||
|
||||
- New core skills when they can live on ClawHub
|
||||
- Commercial service integrations that do not clearly fit the model-provider category
|
||||
- Wrapper channels around already supported channels without a clear capability or security gap
|
||||
- First-class MCP runtime in core when `mcporter` already provides the integration path
|
||||
- Heavy orchestration layers that duplicate existing agent and tool infrastructure
|
||||
|
||||
This list is a roadmap guardrail, not a law of physics.
|
||||
Strong user demand and strong technical rationale can change it.
|
||||
@@ -1,46 +0,0 @@
|
||||
#!/usr/bin/env bun
|
||||
import { existsSync } from 'node:fs'
|
||||
import { stat } from 'node:fs/promises'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const distCliUrl = new URL('./packages/clawdhub/dist/cli.js', import.meta.url)
|
||||
const distCliPath = fileURLToPath(distCliUrl)
|
||||
const srcRootPath = fileURLToPath(new URL('./packages/clawdhub/src/', import.meta.url))
|
||||
|
||||
const shouldBuild = await (async () => {
|
||||
if (!existsSync(distCliPath)) return true
|
||||
try {
|
||||
const dist = await stat(distCliPath)
|
||||
const latestSrcMtime = await getLatestMtime(srcRootPath)
|
||||
return latestSrcMtime > dist.mtimeMs
|
||||
} catch {
|
||||
return true
|
||||
}
|
||||
})()
|
||||
|
||||
if (shouldBuild) {
|
||||
const proc = Bun.spawn(['bunx', 'tsc', '-p', 'packages/clawdhub/tsconfig.json'], {
|
||||
stdin: 'inherit',
|
||||
stdout: 'inherit',
|
||||
stderr: 'inherit',
|
||||
})
|
||||
const code = await proc.exited
|
||||
if (code !== 0) process.exit(code)
|
||||
}
|
||||
|
||||
await import(distCliUrl.href)
|
||||
|
||||
async function getLatestMtime(root: string) {
|
||||
let latest = 0
|
||||
const glob = new Bun.Glob('**/*.ts')
|
||||
for await (const rel of glob.scan({ cwd: root, onlyFiles: true })) {
|
||||
const path = `${root}${root.endsWith('/') ? '' : '/'}${rel}`
|
||||
try {
|
||||
const entry = await stat(path)
|
||||
latest = Math.max(latest, entry.mtimeMs)
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return latest
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
#!/usr/bin/env bun
|
||||
import { existsSync } from 'node:fs'
|
||||
import { stat } from 'node:fs/promises'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const distCliUrl = new URL('./packages/clawdhub/dist/cli.js', import.meta.url)
|
||||
const distCliPath = fileURLToPath(distCliUrl)
|
||||
const srcRootPath = fileURLToPath(new URL('./packages/clawdhub/src/', import.meta.url))
|
||||
|
||||
const shouldBuild = await (async () => {
|
||||
if (!existsSync(distCliPath)) return true
|
||||
try {
|
||||
const dist = await stat(distCliPath)
|
||||
const latestSrcMtime = await getLatestMtime(srcRootPath)
|
||||
return latestSrcMtime > dist.mtimeMs
|
||||
} catch {
|
||||
return true
|
||||
}
|
||||
})()
|
||||
|
||||
if (shouldBuild) {
|
||||
const proc = Bun.spawn(['bunx', 'tsc', '-p', 'packages/clawdhub/tsconfig.json'], {
|
||||
stdin: 'inherit',
|
||||
stdout: 'inherit',
|
||||
stderr: 'inherit',
|
||||
})
|
||||
const code = await proc.exited
|
||||
if (code !== 0) process.exit(code)
|
||||
}
|
||||
|
||||
await import(distCliUrl.href)
|
||||
|
||||
async function getLatestMtime(root: string) {
|
||||
let latest = 0
|
||||
const glob = new Bun.Glob('**/*.ts')
|
||||
for await (const rel of glob.scan({ cwd: root, onlyFiles: true })) {
|
||||
const path = `${root}${root.endsWith('/') ? '' : '/'}${rel}`
|
||||
try {
|
||||
const entry = await stat(path)
|
||||
latest = Math.max(latest, entry.mtimeMs)
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return latest
|
||||
}
|
||||
|
After Width: | Height: | Size: 832 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 214 KiB |
|
After Width: | Height: | Size: 835 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 210 KiB |
@@ -0,0 +1,23 @@
|
||||
# ClawHub UI Proof
|
||||
Status: pass
|
||||
Scenario: `/Users/patrickerichsen/.codex/worktrees/68a3/clawhub/.artifacts/proof-scenarios/sample-text-before-after.pw.ts`
|
||||
Baseline: `origin/main`
|
||||
Candidate: `worktree`
|
||||
Provider: `hetzner`
|
||||
## Artifacts
|
||||
### baseline
|
||||
|
||||
- Output: `/Users/patrickerichsen/.codex/worktrees/68a3/clawhub/.artifacts/clawhub-ui-proof/2026-05-13T00-12-37-146Z/baseline`
|
||||
- pass: baseline /skills - `baseline/screenshots/baseline-skills.png`
|
||||
- pass: baseline /plugins - `baseline/screenshots/baseline-plugins.png`
|
||||
- pass: baseline /souls - `baseline/screenshots/baseline-souls.png`
|
||||
- Video: `baseline/full-run.mp4`
|
||||
|
||||
### candidate
|
||||
|
||||
- Output: `/Users/patrickerichsen/.codex/worktrees/68a3/clawhub/.artifacts/clawhub-ui-proof/2026-05-13T00-12-37-146Z/candidate`
|
||||
- pass: candidate /skills - `candidate/screenshots/candidate-skills.png`
|
||||
- pass: candidate /plugins - `candidate/screenshots/candidate-plugins.png`
|
||||
- pass: candidate /souls - `candidate/screenshots/candidate-souls.png`
|
||||
- Video: `candidate/full-run.mp4`
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"baseline": "origin/main",
|
||||
"candidate": "worktree",
|
||||
"generatedAt": "2026-05-13T00:12:37.148Z",
|
||||
"lanes": [
|
||||
{
|
||||
"localOutputDir": "/Users/patrickerichsen/.codex/worktrees/68a3/clawhub/.artifacts/clawhub-ui-proof/2026-05-13T00-12-37-146Z/baseline",
|
||||
"name": "baseline",
|
||||
"ref": "origin/main",
|
||||
"remoteOutputDir": "/work/crabbox/cbx_2ac97d8c7cd2/clawhub/.artifacts/clawhub-ui-proof/remote-2026-05-13T00-12-37-146Z/baseline",
|
||||
"status": "pass",
|
||||
"steps": [
|
||||
{
|
||||
"lane": "baseline",
|
||||
"name": "baseline /skills",
|
||||
"screenshot": "screenshots/baseline-skills.png",
|
||||
"slug": "baseline-skills",
|
||||
"status": "pass"
|
||||
},
|
||||
{
|
||||
"lane": "baseline",
|
||||
"name": "baseline /plugins",
|
||||
"screenshot": "screenshots/baseline-plugins.png",
|
||||
"slug": "baseline-plugins",
|
||||
"status": "pass"
|
||||
},
|
||||
{
|
||||
"lane": "baseline",
|
||||
"name": "baseline /souls",
|
||||
"screenshot": "screenshots/baseline-souls.png",
|
||||
"slug": "baseline-souls",
|
||||
"status": "pass"
|
||||
}
|
||||
],
|
||||
"videoPath": "/Users/patrickerichsen/.codex/worktrees/68a3/clawhub/.artifacts/clawhub-ui-proof/2026-05-13T00-12-37-146Z/baseline/full-run.mp4"
|
||||
},
|
||||
{
|
||||
"localOutputDir": "/Users/patrickerichsen/.codex/worktrees/68a3/clawhub/.artifacts/clawhub-ui-proof/2026-05-13T00-12-37-146Z/candidate",
|
||||
"name": "candidate",
|
||||
"ref": "worktree",
|
||||
"remoteOutputDir": "/work/crabbox/cbx_2ac97d8c7cd2/clawhub/.artifacts/clawhub-ui-proof/remote-2026-05-13T00-12-37-146Z/candidate",
|
||||
"status": "pass",
|
||||
"steps": [
|
||||
{
|
||||
"lane": "candidate",
|
||||
"name": "candidate /skills",
|
||||
"screenshot": "screenshots/candidate-skills.png",
|
||||
"slug": "candidate-skills",
|
||||
"status": "pass"
|
||||
},
|
||||
{
|
||||
"lane": "candidate",
|
||||
"name": "candidate /plugins",
|
||||
"screenshot": "screenshots/candidate-plugins.png",
|
||||
"slug": "candidate-plugins",
|
||||
"status": "pass"
|
||||
},
|
||||
{
|
||||
"lane": "candidate",
|
||||
"name": "candidate /souls",
|
||||
"screenshot": "screenshots/candidate-souls.png",
|
||||
"slug": "candidate-souls",
|
||||
"status": "pass"
|
||||
}
|
||||
],
|
||||
"videoPath": "/Users/patrickerichsen/.codex/worktrees/68a3/clawhub/.artifacts/clawhub-ui-proof/2026-05-13T00-12-37-146Z/candidate/full-run.mp4"
|
||||
}
|
||||
],
|
||||
"outputDir": "/Users/patrickerichsen/.codex/worktrees/68a3/clawhub/.artifacts/clawhub-ui-proof/2026-05-13T00-12-37-146Z",
|
||||
"provider": "hetzner",
|
||||
"scenario": "/Users/patrickerichsen/.codex/worktrees/68a3/clawhub/.artifacts/proof-scenarios/sample-text-before-after.pw.ts",
|
||||
"status": "pass",
|
||||
"crabbox": {
|
||||
"createdLease": true,
|
||||
"leaseId": "cbx_2ac97d8c7cd2"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 29 KiB |
@@ -0,0 +1,11 @@
|
||||
# ClawHub UI Proof
|
||||
|
||||
Status: pass
|
||||
Mode: `feature`
|
||||
Scenario: `e2e/local-auth/security-scan-management-proof.pw.test.ts`
|
||||
Provider: `local-auth`
|
||||
|
||||
## Artifacts
|
||||
|
||||
- pass: Desktop management security scans - `candidate/screenshots/desktop-security-scans.png`
|
||||
- pass: Mobile management security scans - `candidate/screenshots/mobile-security-scans.png`
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"baseline": "not run",
|
||||
"candidate": "pe/security-scan-admin-tooling",
|
||||
"generatedAt": "2026-05-18T21:32:12.809Z",
|
||||
"lanes": [
|
||||
{
|
||||
"localOutputDir": "/Users/patrickerichsen/Git/openclaw/clawhub/.artifacts/clawhub-ui-proof/2026-05-18T21-29-29Z-security-scans/candidate",
|
||||
"name": "candidate",
|
||||
"ref": "pe/security-scan-admin-tooling",
|
||||
"status": "pass",
|
||||
"steps": [
|
||||
{
|
||||
"lane": "candidate",
|
||||
"name": "Desktop management security scans",
|
||||
"screenshot": "screenshots/desktop-security-scans.png",
|
||||
"slug": "desktop-security-scans",
|
||||
"status": "pass"
|
||||
},
|
||||
{
|
||||
"lane": "candidate",
|
||||
"name": "Mobile management security scans",
|
||||
"screenshot": "screenshots/mobile-security-scans.png",
|
||||
"slug": "mobile-security-scans",
|
||||
"status": "pass"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"mode": "feature",
|
||||
"outputDir": "/Users/patrickerichsen/Git/openclaw/clawhub/.artifacts/clawhub-ui-proof/2026-05-18T21-29-29Z-security-scans",
|
||||
"provider": "local-auth",
|
||||
"scenario": "e2e/local-auth/security-scan-management-proof.pw.test.ts",
|
||||
"status": "pass"
|
||||
}
|
||||
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 100 KiB |
@@ -0,0 +1,5 @@
|
||||
# Owner-Scoped Skill Slugs UI Proof
|
||||
|
||||
- Scenario: owner-scoped skill slug UI surfaces.
|
||||
- Skill detail page proof: owner-qualified route and install command render as `@local/padel`.
|
||||
- Install command proof: copyable command uses `openclaw skills install @local/padel`.
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"status": "passed",
|
||||
"mode": "feature",
|
||||
"scenario": "owner-scoped skill slug UI surfaces",
|
||||
"provider": "Codex local browser proof",
|
||||
"candidate": "pe/owner-scoped-skill-slugs",
|
||||
"lanes": [
|
||||
{
|
||||
"name": "owner-scoped-skill-slugs",
|
||||
"steps": [
|
||||
{
|
||||
"name": "Skill detail page shows owner-qualified route and install ref",
|
||||
"slug": "skill-page-owner-ref",
|
||||
"status": "passed",
|
||||
"screenshot": "skill-page-owner-ref.png"
|
||||
},
|
||||
{
|
||||
"name": "Install command uses @owner/slug",
|
||||
"slug": "install-command-owner-ref",
|
||||
"status": "passed",
|
||||
"screenshot": "install-command-owner-ref.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 593 KiB |
|
After Width: | Height: | Size: 611 KiB |
|
After Width: | Height: | Size: 512 KiB |
@@ -0,0 +1,7 @@
|
||||
# Management Security Scan Overview
|
||||
|
||||
Feature proof for PR #2403.
|
||||
|
||||
- Desktop overview shows ClawScan-first current verdict totals, pipeline status, recent scan window, category rollups, and failed scan samples.
|
||||
- Desktop drilldown shows a selected artifact with ClawScan verdict/category/summary first, followed by pipeline status and supporting scanner evidence.
|
||||
- Mobile view keeps the management security overview usable at narrow width without overlapping controls.
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"status": "passed",
|
||||
"mode": "feature",
|
||||
"scenario": "management-security-scan-overview",
|
||||
"provider": "local-playwright",
|
||||
"candidate": "pe/clawscan-visibility",
|
||||
"lanes": [
|
||||
{
|
||||
"name": "candidate",
|
||||
"steps": [
|
||||
{
|
||||
"name": "Management security overview",
|
||||
"slug": "management-security-overview-desktop",
|
||||
"status": "passed",
|
||||
"screenshot": "management-security-overview-desktop.png"
|
||||
},
|
||||
{
|
||||
"name": "Artifact drilldown",
|
||||
"slug": "management-security-drilldown-desktop",
|
||||
"status": "passed",
|
||||
"screenshot": "management-security-drilldown-desktop.png"
|
||||
},
|
||||
{
|
||||
"name": "Mobile management security overview",
|
||||
"slug": "management-security-mobile",
|
||||
"status": "passed",
|
||||
"screenshot": "management-security-mobile.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 162 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 161 KiB |
|
After Width: | Height: | Size: 61 KiB |
@@ -0,0 +1,12 @@
|
||||
# ClawHub UI Proof
|
||||
|
||||
Status: pass
|
||||
Scenario: Skill grid card metadata layout with nearby skills
|
||||
|
||||
Screenshots:
|
||||
- baseline desktop: baseline/screenshots/desktop-grid-context.png
|
||||
- candidate desktop: candidate/screenshots/desktop-grid-context.png
|
||||
- baseline mobile: baseline/screenshots/mobile-grid-context.png
|
||||
- candidate mobile: candidate/screenshots/mobile-grid-context.png
|
||||
|
||||
Observed target card: Self-Improving + Proactive Agent.
|
||||
@@ -0,0 +1,156 @@
|
||||
{
|
||||
"baseline": "origin/main",
|
||||
"candidate": "jesse/fix-skill-card-date-overlap",
|
||||
"generatedAt": "2026-06-01T16:29:49.092Z",
|
||||
"lanes": [
|
||||
{
|
||||
"name": "baseline",
|
||||
"lane": "baseline",
|
||||
"ref": "origin/main",
|
||||
"baseURL": "http://127.0.0.1:3038",
|
||||
"localOutputDir": "/Users/jmerhi/repos/claw-working-space/clawhub-fix-skill-card-date-overlap/.artifacts/clawhub-ui-proof/skill-card-grid-context-1780331337362/baseline",
|
||||
"status": "pass",
|
||||
"steps": [
|
||||
{
|
||||
"name": "Desktop skills grid context",
|
||||
"slug": "desktop-grid-context",
|
||||
"screenshot": "screenshots/desktop-grid-context.png",
|
||||
"status": "pass"
|
||||
},
|
||||
{
|
||||
"name": "Mobile skills grid context",
|
||||
"slug": "mobile-grid-context",
|
||||
"screenshot": "screenshots/mobile-grid-context.png",
|
||||
"status": "pass"
|
||||
}
|
||||
],
|
||||
"metrics": [
|
||||
{
|
||||
"step": "desktop grid context",
|
||||
"viewport": "desktop",
|
||||
"children": [
|
||||
{
|
||||
"className": "skill-card-tags",
|
||||
"text": "LinuxmacOSWindows"
|
||||
},
|
||||
{
|
||||
"className": "skill-card-header",
|
||||
"text": "Self-Improving + Proactive Agent"
|
||||
},
|
||||
{
|
||||
"className": "skill-card-summary",
|
||||
"text": "Self-reflection + Self-criticism + Self-learning + Self-organizing memory. Agent evaluates its own work, catches mistakes, and improves permanently. Use when..."
|
||||
},
|
||||
{
|
||||
"className": "skill-card-footer",
|
||||
"text": "by@ivangdavilaUpdated 3w ago1.2k·195k"
|
||||
}
|
||||
],
|
||||
"tagsBelowSummary": false,
|
||||
"authorToUpdatedGap": 14
|
||||
},
|
||||
{
|
||||
"step": "mobile grid context",
|
||||
"viewport": "mobile",
|
||||
"children": [
|
||||
{
|
||||
"className": "skill-card-tags",
|
||||
"text": "LinuxmacOSWindows"
|
||||
},
|
||||
{
|
||||
"className": "skill-card-header",
|
||||
"text": "Self-Improving + Proactive Agent"
|
||||
},
|
||||
{
|
||||
"className": "skill-card-summary",
|
||||
"text": "Self-reflection + Self-criticism + Self-learning + Self-organizing memory. Agent evaluates its own work, catches mistakes, and improves permanently. Use when..."
|
||||
},
|
||||
{
|
||||
"className": "skill-card-footer",
|
||||
"text": "by@ivangdavilaUpdated 3w ago1.2k·195k"
|
||||
}
|
||||
],
|
||||
"tagsBelowSummary": false,
|
||||
"authorToUpdatedGap": 14
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "candidate",
|
||||
"lane": "candidate",
|
||||
"ref": "jesse/fix-skill-card-date-overlap",
|
||||
"baseURL": "http://127.0.0.1:3037",
|
||||
"localOutputDir": "/Users/jmerhi/repos/claw-working-space/clawhub-fix-skill-card-date-overlap/.artifacts/clawhub-ui-proof/skill-card-grid-context-1780331337362/candidate",
|
||||
"status": "pass",
|
||||
"steps": [
|
||||
{
|
||||
"name": "Desktop skills grid context",
|
||||
"slug": "desktop-grid-context",
|
||||
"screenshot": "screenshots/desktop-grid-context.png",
|
||||
"status": "pass"
|
||||
},
|
||||
{
|
||||
"name": "Mobile skills grid context",
|
||||
"slug": "mobile-grid-context",
|
||||
"screenshot": "screenshots/mobile-grid-context.png",
|
||||
"status": "pass"
|
||||
}
|
||||
],
|
||||
"metrics": [
|
||||
{
|
||||
"step": "desktop grid context",
|
||||
"viewport": "desktop",
|
||||
"children": [
|
||||
{
|
||||
"className": "skill-card-header",
|
||||
"text": "Self-Improving + Proactive Agent"
|
||||
},
|
||||
{
|
||||
"className": "skill-card-summary",
|
||||
"text": "Self-reflection + Self-criticism + Self-learning + Self-organizing memory. Agent evaluates its own work, catches mistakes, and improves permanently. Use when..."
|
||||
},
|
||||
{
|
||||
"className": "skill-card-tags",
|
||||
"text": "LinuxmacOSWindows"
|
||||
},
|
||||
{
|
||||
"className": "skill-card-footer",
|
||||
"text": "by@ivangdavilaUpdated 3w ago1.2k·195k"
|
||||
}
|
||||
],
|
||||
"tagsBelowSummary": true,
|
||||
"authorToUpdatedGap": 8
|
||||
},
|
||||
{
|
||||
"step": "mobile grid context",
|
||||
"viewport": "mobile",
|
||||
"children": [
|
||||
{
|
||||
"className": "skill-card-header",
|
||||
"text": "Self-Improving + Proactive Agent"
|
||||
},
|
||||
{
|
||||
"className": "skill-card-summary",
|
||||
"text": "Self-reflection + Self-criticism + Self-learning + Self-organizing memory. Agent evaluates its own work, catches mistakes, and improves permanently. Use when..."
|
||||
},
|
||||
{
|
||||
"className": "skill-card-tags",
|
||||
"text": "LinuxmacOSWindows"
|
||||
},
|
||||
{
|
||||
"className": "skill-card-footer",
|
||||
"text": "by@ivangdavilaUpdated 3w ago1.2k·195k"
|
||||
}
|
||||
],
|
||||
"tagsBelowSummary": true,
|
||||
"authorToUpdatedGap": 8
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"mode": "before-after",
|
||||
"outputDir": "/Users/jmerhi/repos/claw-working-space/clawhub-fix-skill-card-date-overlap/.artifacts/clawhub-ui-proof/skill-card-grid-context-1780331337362",
|
||||
"provider": "local",
|
||||
"scenario": "Skill grid card metadata layout with nearby skills",
|
||||
"status": "pass"
|
||||
}
|
||||
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,6 @@
|
||||
# ClawHub UI Proof
|
||||
|
||||
Status: pass
|
||||
Mode: before-after
|
||||
Scenario: Skill grid card metadata layout
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"baseline": "origin/main",
|
||||
"candidate": "jesse/fix-skill-card-date-overlap",
|
||||
"lanes": [
|
||||
{
|
||||
"baseURL": "http://127.0.0.1:3038",
|
||||
"lane": "baseline",
|
||||
"name": "baseline",
|
||||
"localOutputDir": "/Users/jmerhi/repos/claw-working-space/clawhub-fix-skill-card-date-overlap/.artifacts/clawhub-ui-proof/skill-card-metadata-1780328491887/baseline",
|
||||
"ref": "origin/main",
|
||||
"status": "pass",
|
||||
"steps": [
|
||||
{
|
||||
"name": "Desktop skill card",
|
||||
"slug": "desktop-skill-card",
|
||||
"screenshot": "screenshots/desktop-skill-card.png",
|
||||
"status": "pass"
|
||||
},
|
||||
{
|
||||
"name": "Mobile skill card",
|
||||
"slug": "mobile-skill-card",
|
||||
"screenshot": "screenshots/mobile-skill-card.png",
|
||||
"status": "pass"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"baseURL": "http://127.0.0.1:3037",
|
||||
"lane": "candidate",
|
||||
"name": "candidate",
|
||||
"localOutputDir": "/Users/jmerhi/repos/claw-working-space/clawhub-fix-skill-card-date-overlap/.artifacts/clawhub-ui-proof/skill-card-metadata-1780328491887/candidate",
|
||||
"ref": "jesse/fix-skill-card-date-overlap",
|
||||
"status": "pass",
|
||||
"steps": [
|
||||
{
|
||||
"name": "Desktop skill card",
|
||||
"slug": "desktop-skill-card",
|
||||
"screenshot": "screenshots/desktop-skill-card.png",
|
||||
"status": "pass"
|
||||
},
|
||||
{
|
||||
"name": "Mobile skill card",
|
||||
"slug": "mobile-skill-card",
|
||||
"screenshot": "screenshots/mobile-skill-card.png",
|
||||
"status": "pass"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"mode": "before-after",
|
||||
"outputDir": "/Users/jmerhi/repos/claw-working-space/clawhub-fix-skill-card-date-overlap/.artifacts/clawhub-ui-proof/skill-card-metadata-1780328491887",
|
||||
"provider": "local",
|
||||
"scenario": "Skill grid card metadata layout",
|
||||
"status": "pass"
|
||||
}
|
||||
|
After Width: | Height: | Size: 74 KiB |
@@ -0,0 +1,14 @@
|
||||
# ClawHub UI Proof
|
||||
|
||||
Status: `passed`
|
||||
|
||||
Mode: `feature`
|
||||
|
||||
Scenario: `manual-plugin-download-counts`
|
||||
|
||||
Provider: `local-playwright`
|
||||
|
||||
## Candidate
|
||||
|
||||
- `http://127.0.0.1:3001/plugins/clawbits-openclaw-plugin`
|
||||
- Confirms plugin detail pages render `Downloads` as the first sidebar stat, above repository and owner metadata.
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"status": "passed",
|
||||
"mode": "feature",
|
||||
"scenario": "manual-plugin-download-counts",
|
||||
"provider": "local-playwright",
|
||||
"baseline": "not-run",
|
||||
"candidate": "pe/plugin-download-counts",
|
||||
"lanes": [
|
||||
{
|
||||
"name": "candidate",
|
||||
"steps": [
|
||||
{
|
||||
"name": "Plugin detail downloads top stat",
|
||||
"slug": "plugin-downloads-top",
|
||||
"status": "passed",
|
||||
"screenshot": "plugin-downloads-top.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 52 KiB |
@@ -0,0 +1,6 @@
|
||||
# ClawHub UI Proof
|
||||
|
||||
- Status: passed
|
||||
- Mode: feature
|
||||
- Scenario: plugin-list-downloads-sort
|
||||
- Proof: plugin list shows the Most downloaded sort option selected and download counts in list rows.
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"status": "passed",
|
||||
"mode": "feature",
|
||||
"scenario": "plugin-list-downloads-sort",
|
||||
"provider": "codex-in-app-browser",
|
||||
"candidate": "pe/plugin-download-counts",
|
||||
"lanes": [
|
||||
{
|
||||
"name": "candidate",
|
||||
"steps": [
|
||||
{
|
||||
"name": "Plugin list downloads and sort",
|
||||
"slug": "plugin-list-downloads-sort",
|
||||
"status": "passed",
|
||||
"screenshot": "plugin-list-downloads-sort.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 30 KiB |
@@ -0,0 +1,6 @@
|
||||
# ClawHub UI Proof
|
||||
|
||||
- Status: passed
|
||||
- Mode: feature
|
||||
- Scenario: plugin-list-no-family-badges
|
||||
- Proof: plugin list still shows download counts while Code Plugin and Bundle Plugin family badges are absent.
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"status": "passed",
|
||||
"mode": "feature",
|
||||
"scenario": "plugin-list-no-family-badges",
|
||||
"provider": "codex-in-app-browser",
|
||||
"candidate": "pe/plugin-download-counts",
|
||||
"lanes": [
|
||||
{
|
||||
"name": "candidate",
|
||||
"steps": [
|
||||
{
|
||||
"name": "Plugin list without family badges",
|
||||
"slug": "plugin-list-no-family-badges",
|
||||
"status": "passed",
|
||||
"screenshot": "plugin-list-no-family-badges.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 124 KiB |
@@ -0,0 +1,6 @@
|
||||
# PR #2520 proof
|
||||
|
||||
Status: pass
|
||||
|
||||
- Rendered the account-ban and artifact-level scanner rejection emails from the real email builders; the account-ban email no longer includes scan-results appeal guidance, while the artifact-level email still includes local scan guidance.
|
||||
- Captured the dedicated banned-account appeal page from a running local ClawHub preview after `/dashboard?error_description=Account%20banned` redirected to `/account-banned`.
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"generatedAt": "2026-06-05T23:54:26.000Z",
|
||||
"mode": "feature",
|
||||
"status": "pass",
|
||||
"provider": "rendered email builder plus live in-app browser preview",
|
||||
"scenario": "account-ban email without scan-results block plus dedicated banned-account route",
|
||||
"candidate": "worktree 3b4cc2d9",
|
||||
"outputDir": ".artifacts/pr-2520-proof",
|
||||
"lanes": [
|
||||
{
|
||||
"name": "candidate",
|
||||
"ref": "worktree 3b4cc2d9",
|
||||
"status": "pass",
|
||||
"steps": [
|
||||
{
|
||||
"lane": "candidate",
|
||||
"name": "Rendered moderation emails",
|
||||
"slug": "rendered-emails",
|
||||
"status": "pass",
|
||||
"screenshot": "screenshots/rendered-emails.png"
|
||||
},
|
||||
{
|
||||
"lane": "candidate",
|
||||
"name": "Dedicated banned-account appeal page",
|
||||
"slug": "banned-sign-in",
|
||||
"status": "pass",
|
||||
"screenshot": "screenshots/banned-sign-in.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 119 KiB |
@@ -0,0 +1,6 @@
|
||||
# PR #2520 proof
|
||||
|
||||
Status: pass
|
||||
|
||||
- Rendered the account-ban and artifact-level scanner rejection emails from the real email builders.
|
||||
- Captured the banned-account sign-in copy from a full-stack local ClawHub preview with local Convex on `/dashboard?error_description=Account%20banned`.
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"generatedAt": "2026-06-05T23:09:45.000Z",
|
||||
"mode": "feature",
|
||||
"status": "pass",
|
||||
"provider": "rendered email builder plus full-stack local-auth Playwright",
|
||||
"scenario": "email builder rendering plus live ClawHub dashboard auth-error route",
|
||||
"candidate": "worktree 03bc802e",
|
||||
"outputDir": ".artifacts/pr-2520-proof",
|
||||
"lanes": [
|
||||
{
|
||||
"name": "candidate",
|
||||
"ref": "worktree 03bc802e",
|
||||
"status": "pass",
|
||||
"steps": [
|
||||
{
|
||||
"lane": "candidate",
|
||||
"name": "Rendered moderation emails",
|
||||
"slug": "rendered-emails",
|
||||
"status": "pass",
|
||||
"screenshot": "screenshots/rendered-emails.png"
|
||||
},
|
||||
{
|
||||
"lane": "candidate",
|
||||
"name": "Live banned-account dashboard sign-in copy",
|
||||
"slug": "banned-sign-in",
|
||||
"status": "pass",
|
||||
"screenshot": "screenshots/banned-sign-in.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 119 KiB |
@@ -0,0 +1,6 @@
|
||||
# PR #2520 proof
|
||||
|
||||
Status: pass
|
||||
|
||||
- Rendered the account-ban and artifact-level scanner rejection emails from the real email builders.
|
||||
- Captured the banned-account sign-in copy from a full-stack local ClawHub preview with local Convex on `/dashboard?error_description=Account%20banned`.
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"generatedAt": "2026-06-05T23:09:45.000Z",
|
||||
"mode": "feature",
|
||||
"status": "pass",
|
||||
"provider": "rendered email builder plus full-stack local-auth Playwright",
|
||||
"scenario": "email builder rendering plus live ClawHub dashboard auth-error route",
|
||||
"candidate": "worktree 03bc802e",
|
||||
"outputDir": ".artifacts/pr-2520-proof",
|
||||
"lanes": [
|
||||
{
|
||||
"name": "candidate",
|
||||
"ref": "worktree 03bc802e",
|
||||
"status": "pass",
|
||||
"steps": [
|
||||
{
|
||||
"lane": "candidate",
|
||||
"name": "Rendered moderation emails",
|
||||
"slug": "rendered-emails",
|
||||
"status": "pass",
|
||||
"screenshot": "screenshots/rendered-emails.png"
|
||||
},
|
||||
{
|
||||
"lane": "candidate",
|
||||
"name": "Live banned-account dashboard sign-in copy",
|
||||
"slug": "banned-sign-in",
|
||||
"status": "pass",
|
||||
"screenshot": "screenshots/banned-sign-in.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 350 KiB |
|
After Width: | Height: | Size: 332 KiB |
@@ -0,0 +1,13 @@
|
||||
# PR 2520 live local proof
|
||||
|
||||
Status: pass
|
||||
|
||||
Captured from a live local ClawHub dev server started with `bun run dev` at `http://localhost:3000`.
|
||||
|
||||
Screenshots cover:
|
||||
|
||||
- dedicated account-banned page at desktop and mobile widths
|
||||
- moderation email output generated from `convex/lib/emails.ts` and served through the same local ClawHub dev server
|
||||
- account-ban email appeal-only copy
|
||||
- skill rejection email with `clawhub scan download demo-skill --version 1.2.3`
|
||||
- plugin rejection email with `clawhub scan download @scope/demo --version 2.0.0 --kind plugin`
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"status": "pass",
|
||||
"mode": "feature",
|
||||
"provider": "local ClawHub dev server",
|
||||
"localServer": "bun run dev -> http://localhost:3000",
|
||||
"commit": "03bcca63",
|
||||
"generatedAt": "2026-06-06T00:39:17.133Z",
|
||||
"screenshots": [
|
||||
{
|
||||
"slug": "account-banned-desktop",
|
||||
"url": "http://localhost:3000/account-banned",
|
||||
"viewport": {
|
||||
"width": 1440,
|
||||
"height": 980
|
||||
},
|
||||
"screenshot": "candidate/screenshots/account-banned-desktop.png"
|
||||
},
|
||||
{
|
||||
"slug": "account-banned-mobile",
|
||||
"url": "http://localhost:3000/account-banned",
|
||||
"viewport": {
|
||||
"width": 390,
|
||||
"height": 844
|
||||
},
|
||||
"screenshot": "candidate/screenshots/account-banned-mobile.png"
|
||||
},
|
||||
{
|
||||
"slug": "moderation-emails-desktop",
|
||||
"url": "http://localhost:3000/__pr-2520-email-proof.html",
|
||||
"viewport": {
|
||||
"width": 1440,
|
||||
"height": 1200
|
||||
},
|
||||
"screenshot": "candidate/screenshots/moderation-emails-desktop.png"
|
||||
},
|
||||
{
|
||||
"slug": "moderation-emails-mobile",
|
||||
"url": "http://localhost:3000/__pr-2520-email-proof.html",
|
||||
"viewport": {
|
||||
"width": 390,
|
||||
"height": 1200
|
||||
},
|
||||
"screenshot": "candidate/screenshots/moderation-emails-mobile.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 30 KiB |
@@ -0,0 +1,6 @@
|
||||
# ClawHub UI Proof
|
||||
|
||||
- Status: passed
|
||||
- Mode: feature
|
||||
- Scenario: plugin-list-no-family-badges
|
||||
- Proof: plugin list still shows download counts while Code Plugin and Bundle Plugin family badges are absent.
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"status": "passed",
|
||||
"mode": "feature",
|
||||
"scenario": "plugin-list-no-family-badges",
|
||||
"provider": "codex-in-app-browser",
|
||||
"candidate": "pe/plugin-download-counts",
|
||||
"lanes": [
|
||||
{
|
||||
"name": "candidate",
|
||||
"steps": [
|
||||
{
|
||||
"name": "Plugin list without family badges",
|
||||
"slug": "plugin-list-no-family-badges",
|
||||
"status": "passed",
|
||||
"screenshot": "plugin-list-no-family-badges.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 44 KiB |
@@ -0,0 +1,6 @@
|
||||
# ClawHub UI Proof
|
||||
|
||||
Status: pass
|
||||
|
||||
- Account deletion confirmation renders one row per affected skill/plugin, with icon, name, publisher handle, and type badge.
|
||||
- Post-cleanup navigation to the deleted plugin shows `Plugin not found`, confirming the resource was removed by the account deletion flow.
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"status": "pass",
|
||||
"mode": "feature",
|
||||
"scenario": "e2e/local-auth/delete-account-resources.pw.test.ts",
|
||||
"provider": "local-auth Playwright",
|
||||
"baseline": null,
|
||||
"candidate": "pe/account-deletion-hard-delete",
|
||||
"generatedAt": "2026-06-06T00:37:39.268Z",
|
||||
"lanes": [
|
||||
{
|
||||
"name": "candidate",
|
||||
"ref": "pe/account-deletion-hard-delete",
|
||||
"status": "pass",
|
||||
"steps": [
|
||||
{
|
||||
"lane": "candidate",
|
||||
"name": "Account deletion confirmation lists each resource row",
|
||||
"screenshot": "screenshots/account-deletion-confirmation.png",
|
||||
"slug": "account-deletion-confirmation",
|
||||
"status": "pass"
|
||||
},
|
||||
{
|
||||
"lane": "candidate",
|
||||
"name": "Deleted plugin route shows resource removed",
|
||||
"screenshot": "screenshots/account-deletion-post-cleanup.png",
|
||||
"slug": "account-deletion-post-cleanup",
|
||||
"status": "pass"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 156 KiB |
@@ -0,0 +1,10 @@
|
||||
# Skill Settings Delete Action
|
||||
|
||||
Real-browser feature proof for the skill settings delete action.
|
||||
|
||||
- Route: local-auth seeded skill settings page
|
||||
- Browser: Playwright chromium
|
||||
- Candidate: pe/skill-settings-delete-action
|
||||
- Screenshots:
|
||||
- `local/delete-action.png`
|
||||
- `local/delete-dialog.png`
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"status": "passed",
|
||||
"mode": "feature",
|
||||
"scenario": "skill-settings-delete-action",
|
||||
"provider": "local-auth Playwright chromium",
|
||||
"candidate": "pe/skill-settings-delete-action",
|
||||
"lanes": [
|
||||
{
|
||||
"name": "local",
|
||||
"steps": [
|
||||
{
|
||||
"name": "Skill settings delete action",
|
||||
"slug": "delete-action",
|
||||
"status": "passed",
|
||||
"screenshot": "delete-action.png"
|
||||
},
|
||||
{
|
||||
"name": "Skill settings delete confirmation dialog",
|
||||
"slug": "delete-dialog",
|
||||
"status": "passed",
|
||||
"screenshot": "delete-dialog.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 505 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 439 KiB |
@@ -0,0 +1,11 @@
|
||||
# PR 2581 prod-backed UI proof
|
||||
|
||||
Status: passed
|
||||
Mode: feature
|
||||
Backend: production Convex read data (`wry-manatee-359`).
|
||||
Pages captured:
|
||||
- `/skills?sort=installs&dir=desc` showing prod skill rows and install sort.
|
||||
- `/search?q=swarm` showing prod search results.
|
||||
- `/chair4ce/swarm` showing a prod-backed skill detail page.
|
||||
|
||||
Note: default `/plugins` was not used because this PR head can request `sort=recommended`, which requires matching backend code that is not deployed to prod yet.
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"status": "passed",
|
||||
"mode": "feature",
|
||||
"scenario": "manual prod-backed PR proof: skills browse, search, and detail",
|
||||
"provider": "local Playwright against http://127.0.0.1:3007 with prod Convex",
|
||||
"candidate": "PR #2581 rebased head f43b8ed3",
|
||||
"lanes": [
|
||||
{
|
||||
"name": "candidate",
|
||||
"steps": [
|
||||
{
|
||||
"name": "Skills browse sorted by installs",
|
||||
"slug": "skills-installs",
|
||||
"status": "passed",
|
||||
"screenshot": "skills-installs.png"
|
||||
},
|
||||
{
|
||||
"name": "Search results for swarm",
|
||||
"slug": "search-swarm",
|
||||
"status": "passed",
|
||||
"screenshot": "search-swarm.png"
|
||||
},
|
||||
{
|
||||
"name": "Skill detail for chair4ce/swarm",
|
||||
"slug": "skill-detail-swarm",
|
||||
"status": "passed",
|
||||
"screenshot": "skill-detail-swarm.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 691 KiB |