Compare commits

..
Author SHA1 Message Date
github-actions[bot] d238ec7ff9 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3467/2026-08-14T01-11-09-088Z 2026-08-13 18:11:52 -07:00
github-actions[bot] 98f8b8f7b0 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3450/2026-08-11T19-53-08-476Z 2026-08-11 12:54:07 -07:00
github-actions[bot] 2d936369b4 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3450/2026-08-11T19-50-37-230Z 2026-08-11 12:51:44 -07:00
github-actions[bot] 41c0469a60 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3450/2026-08-11T18-10-17-898Z 2026-08-11 11:19:18 -07:00
github-actions[bot] f140f6d83d qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3434/home-plugin-featured-final 2026-08-06 18:32:47 -03:00
github-actions[bot] 03a55fb8f7 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3427/pr3427-final-6d01ae35-v6 2026-08-06 17:07:02 -03:00
github-actions[bot] b9acb415aa qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3427/pr3427-final-d965b62f-v5 2026-08-06 17:00:57 -03:00
github-actions[bot] e47b15169e qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3418/pr3418-local-final-6 2026-08-06 16:05:25 -03:00
github-actions[bot] c1d439f83c qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3427/responsive-icons-final-d2e9cbb6-v3 2026-08-05 22:46:21 -03:00
github-actions[bot] 9cafb7c376 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3418/2026-08-06T01-26-25-116Z 2026-08-05 22:27:43 -03:00
github-actions[bot] 0acbc866cf qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3418/2026-08-06T01-18-20-016Z 2026-08-05 22:19:59 -03:00
github-actions[bot] b01216e6ed qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3424/2026-08-06T00-38-23-233Z 2026-08-05 21:46:13 -03:00
github-actions[bot] c6a9d37840 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3418/2026-08-06T00-20-45-507Z 2026-08-05 21:22:15 -03:00
github-actions[bot] 5266bc6456 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3430/2026-08-05-nvidia-evals 2026-08-05 17:15:34 -07:00
github-actions[bot] b53ab3f6ad qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3428/pr-3428-7bd70630-selection-final 2026-08-05 21:13:52 -03:00
github-actions[bot] f5fe3ff444 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3430/2026-08-05-nvidia-evals 2026-08-05 17:10:27 -07:00
github-actions[bot] 5538ff53b8 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3427/discovery-icon-hierarchy 2026-08-05 19:56:57 -03:00
github-actions[bot] 2f8439e23e qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3426/official-publisher-activity-local-proof 2026-08-05 19:48:12 -03:00
github-actions[bot] 7aae2d0ce5 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3423/skills-sh-trending-proof 2026-08-05 19:43:18 -03:00
github-actions[bot] 4e8815069c qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3418/home-catalog-discovery-local 2026-08-05 19:19:45 -03:00
github-actions[bot] 787f71d3ed qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3415/2026-08-05T11-58-00 2026-08-05 12:03:58 -07:00
github-actions[bot] af7a8930e8 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3415/2026-08-05T11-58-00 2026-08-05 12:01:00 -07:00
github-actions[bot] b75dfa14b8 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3399/skills-ssr-budget-d40c81f4 2026-08-05 14:07:56 -03:00
github-actions[bot] 66fe641c0e qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3398/font-bundles-f01a6e90 2026-08-05 14:07:38 -03:00
github-actions[bot] 66de47afcb qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3403/carapace-v061-sparkline 2026-08-04 17:41:48 -07:00
github-actions[bot] 9647ec07ca qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3403/carapace-v061-sparkline 2026-08-04 17:17:58 -07:00
github-actions[bot] 4398c5061e qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3402/2026-08-04-carapace-download-trend 2026-08-04 16:34:28 -07:00
github-actions[bot] fe849db257 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3399/skills-canonical-ssr 2026-08-04 14:04:06 -03:00
github-actions[bot] 8a3561c551 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3399/skills-canonical-ssr 2026-08-04 14:02:35 -03:00
github-actions[bot] 8712206499 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3398/font-bundles-01cb52aa 2026-08-04 13:48:18 -03:00
github-actions[bot] ca8ec4e92c qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3281/manual 2026-08-03 13:33:35 -03:00
github-actions[bot] 25df458b5d qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3376/pr-3376-local 2026-08-02 19:41:48 -07:00
github-actions[bot] 598e495175 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3364/clawhub-pr-3364-proof 2026-07-31 16:03:42 -07:00
github-actions[bot] 18f50c85ea qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3361/2026-07-31-skill-header-alignment 2026-07-31 14:55:41 -07:00
github-actions[bot] 021b9ad2e8 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3334/publish 2026-07-30 20:30:17 -07:00
github-actions[bot] 1c13c5b7a3 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3321/claw-625 2026-07-30 14:26:52 -07:00
github-actions[bot] b0035d7771 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3320/2026-07-30T12-45-00-category-spacing-followup 2026-07-30 12:43:37 -07:00
github-actions[bot] 6b451bf47e qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3315/2026-07-30T10-18-00 2026-07-30 10:18:35 -07:00
github-actions[bot] e9ffcab695 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3228/claw-561-bookmarks 2026-07-27 15:16:32 -05:00
github-actions[bot] 836d575374 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3228/claw-561-bookmarks 2026-07-27 15:05:02 -05:00
github-actions[bot] 8f01ec8ed8 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3283/2026-07-27-official-skills-mobile 2026-07-27 16:39:09 -03:00
github-actions[bot] baabfa40b5 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3281/manual 2026-07-27 16:24:42 -03:00
github-actions[bot] 7cf1043fae qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3281/manual 2026-07-27 16:17:50 -03:00
github-actions[bot] 845fc5050d qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3269/social-skill-icon 2026-07-26 13:20:29 -05:00
github-actions[bot] a4972acb93 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3268/clawhub-icon-proof-3268 2026-07-26 12:36:41 -05:00
github-actions[bot] 6069fc3f07 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3267/pr-3267-11a7840 2026-07-26 10:53:16 -03:00
github-actions[bot] 5ea6905b19 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3264/claw-577-mixed-search 2026-07-24 22:15:05 -05:00
github-actions[bot] 8acfa5aa78 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3260/pr-3260-proof 2026-07-24 18:19:11 -05:00
github-actions[bot] 3d315c96dd qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3243/trending-card-stats-proof 2026-07-23 12:30:44 -07:00
github-actions[bot] 9dcf246bc2 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3240/clawhub-official-ui-proof 2026-07-23 10:56:16 -07:00
github-actions[bot] 0d1b14faf5 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3230/2026-07-22-claw560 2026-07-22 14:36:53 -07:00
github-actions[bot] 74d346f5a2 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3199/20260721-claw-575-owner-version-restore 2026-07-20 19:42:22 -07:00
github-actions[bot] e86050b1bc qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3141/pr-3141-local-20260717-223208 2026-07-17 22:59:20 -03:00
github-actions[bot] 07791fe470 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3141/pr-3141-local-20260717-223208 2026-07-17 22:54:27 -03:00
github-actions[bot] de1d1dc848 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3169/clawhub-ui-proof-3148 2026-07-17 17:56:24 -07:00
github-actions[bot] a7a537aac0 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3155/pr-3155-browse-polish 2026-07-17 10:41:21 -07:00
github-actions[bot] 618400f40c qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3126/proof 2026-07-16 19:02:23 -07:00
github-actions[bot] 66e762fe87 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3126/proof 2026-07-16 17:17:20 -07:00
github-actions[bot] 3674dd72ca qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3121/publish 2026-07-16 15:19:36 -07:00
github-actions[bot] d8549a7ac3 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3121/publish 2026-07-16 13:41:39 -07:00
github-actions[bot] 8f7bba35ff qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3121/publish 2026-07-16 12:23:49 -07:00
github-actions[bot] b434eb4c83 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3120/static-hero-proof 2026-07-16 12:12:45 -07:00
github-actions[bot] 7f4107ba81 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3108/2026-07-16-home-hero-centering 2026-07-16 11:47:30 -03:00
github-actions[bot] 9ee3d3ffad qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3062/ssr-plugin-catalog-reference 2026-07-13 13:05:31 -03:00
github-actions[bot] d683d05a3c qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3073/3064-publisher-reads 2026-07-13 10:25:23 -03:00
github-actions[bot] 099f002089 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3072/3065-lazy-histories 2026-07-13 09:21:31 -03:00
github-actions[bot] 9e6d801418 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3071/3066-offscreen-images 2026-07-13 09:02:38 -03:00
github-actions[bot] 538c2c0713 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-3070/2026-07-13-pr-3070 2026-07-13 09:01:44 -03:00
github-actions[bot] 3ad8006f64 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2962/pr-2962-local 2026-07-11 11:02:49 -03:00
github-actions[bot] 6e986b1e41 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2977/clawhub-promotion-padding-proof 2026-07-06 12:24:38 -05:00
github-actions[bot] 4dbc18e490 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2853/clawhub-verified-ui-proof 2026-06-24 21:22:47 -07:00
github-actions[bot] 4c7ec72c8e qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2849/remove-hero-category-commas 2026-06-24 09:21:10 -07:00
github-actions[bot] 5cba745702 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2831/clawhub-creator-kind-proof 2026-06-23 21:19:18 -07:00
github-actions[bot] aa6fa9d39c qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2827/clawhub-creators-proof 2026-06-23 18:58:04 -07:00
github-actions[bot] 6f5a5312bc qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2824/official-typeahead-badge 2026-06-23 17:02:53 -07:00
github-actions[bot] 7b7bd713e3 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2813/expedia-route 2026-06-23 15:03:00 -07:00
github-actions[bot] 84bb6339a8 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2785/clawhub-banned-proof-hYjWLS 2026-06-22 18:01:05 -07:00
github-actions[bot] 55b3a9dbe3 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2765/pr-2765-hero-proof 2026-06-22 13:13:06 -07:00
github-actions[bot] 406d02599c qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2782/clawhub-scoped-plugin-proof.t6kDst 2026-06-22 12:44:25 -07:00
github-actions[bot] 1f29641fb3 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2781/proof 2026-06-22 12:25:14 -07:00
github-actions[bot] f048c9adc0 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2759/claw-371-split-tabs-proof 2026-06-19 18:27:56 -07:00
github-actions[bot] 8c62dc88f1 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2759/claw-371-split-tabs-proof 2026-06-19 18:22:38 -07:00
github-actions[bot] 1d75ea93f4 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2759/claw-371-pr-proof 2026-06-19 17:21:46 -07:00
github-actions[bot] c83dc7a42c qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2748/pr-2748-local 2026-06-18 22:45:50 -06:00
github-actions[bot] 88ef239b76 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2747/claw-359-github 2026-06-18 19:35:26 -07:00
github-actions[bot] 221ff269fd qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2747/claw-359-github 2026-06-18 19:31:57 -07:00
github-actions[bot] 07ebe1e23e qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2745/clawhub-claw-357-proof 2026-06-18 18:45:35 -07:00
github-actions[bot] d6786c1ef1 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2745/clawhub-claw-357-proof 2026-06-18 18:29:44 -07:00
github-actions[bot] 7ed0334696 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2738/clawhub-email-proof-bundle 2026-06-18 16:17:31 -07:00
github-actions[bot] 0fc7fb2993 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2732/local-category-topics 2026-06-18 14:11:45 -06:00
github-actions[bot] 62676305da qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2732/sidebar-topics-ead31cc2 2026-06-18 13:33:50 -06:00
github-actions[bot] 5999247584 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2299/clawhub-pr-2299-owner-scoped-proof 2026-06-17 14:09:38 -07:00
github-actions[bot] 5ac1acef42 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2699/pr-2699-catalog-metadata-edit-preview 2026-06-17 06:20:51 -06:00
github-actions[bot] 0188f16f04 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2699/pr-2699-catalog-metadata-edit-preview 2026-06-17 05:55:09 -06:00
github-actions[bot] 297e95b9a4 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2699/taxonomy-pr1 2026-06-16 21:57:19 -06:00
github-actions[bot] 26af383cf8 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2697/clawhub-pr-2697-publisher-abuse-email-proof 2026-06-16 17:42:18 -07:00
github-actions[bot] 47c519ba69 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2686/local-exact-head-mobile 2026-06-16 14:22:39 -06:00
github-actions[bot] a7c82ecd88 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2686/local-pr-2686 2026-06-16 07:29:15 -06:00
github-actions[bot] fa8864e49d qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2664/claw-333-version-delete-final 2026-06-15 17:43:19 -07:00
github-actions[bot] 2339a744d4 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2661/clawhub-remove-home-proof-bar-proof 2026-06-15 17:16:11 -07:00
github-actions[bot] 69d5ef4c72 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2657/clawhub-content-rights-proof 2026-06-15 16:38:25 -07:00
github-actions[bot] bd4762be9f qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2646/claw333-pr-proof 2026-06-14 20:36:48 -07:00
github-actions[bot] beaa5aecad qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2640/theme-menu-row-proof-publish 2026-06-14 19:47:22 -07:00
github-actions[bot] 8fdb9224b2 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2581/pr-2581-prod-data-2026-06-15T00-56-51-869Z 2026-06-15 10:57:15 +10:00
github-actions[bot] 99790afd64 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2633/pr-2633-install-ui 2026-06-15 10:53:18 +10:00
github-actions[bot] 93f57b6c83 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2632/clawhub-header-proof.XXXXXX.IsR7TFeEuo 2026-06-14 16:36:38 -07:00
github-actions[bot] c148e51c1a qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2609/proof 2026-06-12 18:49:43 -07:00
github-actions[bot] 7f51db60eb qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2616/clawhub-2615-ui-proof 2026-06-12 10:39:02 -07:00
github-actions[bot] 8e8227978c qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2597/clawhub-email-proof-structured-XXXXXX.fGbkx7esrH 2026-06-11 17:06:11 -07:00
github-actions[bot] 0da9bce27c qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2597/email-template-proof 2026-06-11 15:39:55 -07:00
github-actions[bot] e0e4def7e0 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2597/claw-283-email-proof 2026-06-11 15:37:43 -07:00
github-actions[bot] 75b4af13ac qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2548/skill-delete-settings 2026-06-08 01:38:03 -07:00
Patrick Erichsen 33a47200f1 Upload scan report for globalcaos teams-hack 1.0.2 2026-06-06 17:15:24 -07:00
Patrick Erichsen c4c142b6fa docs: add pr 2520 live local proof artifacts 2026-06-05 17:39:18 -07:00
github-actions[bot] b8eee3a668 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2533/account-deletion-modal-20260605173739 2026-06-05 17:37:45 -07:00
Patrick Erichsen 4222a94ad9 qa: scrub banned user proof fixture handle 2026-06-05 17:20:57 -07:00
github-actions[bot] 94027972d8 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2520/appeals-flow-account-banned-3b4cc2d9 2026-06-05 16:54:38 -07:00
Patrick Erichsen 91601c2395 qa: remove generated banned user proof card 2026-06-05 16:17:14 -07:00
Patrick Erichsen 623c77c9e3 qa: add real browser proof for banned user profiles 2026-06-05 16:16:43 -07:00
github-actions[bot] cb1b807d22 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2529/2026-06-05-plugin-list-no-family-badges 2026-06-05 16:14:24 -07:00
github-actions[bot] 8f8e07c270 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2520/appeals-flow-proof-live-auth-03bc802e 2026-06-05 16:11:11 -07:00
github-actions[bot] 5cc7e02544 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2484/2026-06-05-plugin-list-no-family-badges 2026-06-05 16:10:22 -07:00
github-actions[bot] 90e4e7ee9b qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2520/appeals-flow-proof-03bc802e 2026-06-05 16:10:09 -07:00
github-actions[bot] 95be288c27 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2520/appeals-flow-proof-03bc802e 2026-06-05 16:05:22 -07:00
Patrick Erichsen d5305b3d78 qa: add banned user profile proof 2026-06-05 15:47:22 -07:00
github-actions[bot] 1caec236fa qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2484/2026-06-05-plugin-list-downloads 2026-06-05 15:27:49 -07:00
Patrick Erichsen 14e71d6b4a qa: add publisher org tabs screenshot 2026-06-04 19:00:40 -07:00
Patrick Erichsen 5918258de9 qa: add auth callback retry toast screenshot 2026-06-04 16:20:37 -07:00
Patrick Erichsen a7561c8b6c qa: add account issue link screenshot 2026-06-04 14:35:26 -07:00
github-actions[bot] 92ccdf82be qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2484/2026-06-03-plugin-download-counts 2026-06-03 14:39:00 -07:00
github-actions[bot] 47a7a8db80 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2465/skill-card-grid-context-1780331337362 2026-06-01 09:33:48 -07:00
github-actions[bot] 353ee15fce qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2465/skill-card-metadata-1780328491887 2026-06-01 08:44:32 -07:00
github-actions[bot] 346da20fe4 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2403/claw-175-local 2026-05-25 19:17:13 -07:00
github-actions[bot] 8c6db59def qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2298/2026-05-18T21-29-29Z-security-scans 2026-05-18 14:32:28 -07:00
github-actions[bot] 39ee8b1d24 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2192/2026-05-13T00-12-37-146Z 2026-05-12 21:09:39 -07:00
github-actions[bot] e5b86164e1 qa: publish ClawHub UI proof for clawhub-ui-proof/pr-2192/2026-05-13T00-12-37-146Z 2026-05-12 21:03:37 -07:00
1202 changed files with 6406 additions and 124131 deletions
-19
View File
@@ -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=
-48
View File
@@ -1,48 +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
env:
VITE_CONVEX_URL: https://example.invalid
- name: Coverage
run: bun run coverage
env:
VITE_CONVEX_URL: https://example.invalid
- name: ClawHub CLI Verify
run: bun run --cwd packages/clawhub verify
- name: Typecheck
run: |
bunx tsc --noEmit
bunx tsc -p packages/schema/tsconfig.json --noEmit
bunx tsc -p packages/clawhub/tsconfig.json --noEmit
- name: Build
run: bun run build
@@ -1,314 +0,0 @@
name: ClawHub CLI NPM Release
on:
workflow_dispatch:
inputs:
tag:
description: Release tag to publish, for example v0.10.0
required: true
type: string
preflight_only:
description: Run validation/build only and skip the gated publish job
required: true
default: false
type: boolean
preflight_run_id:
description: Existing successful preflight workflow run id to promote without rebuilding
required: false
type: string
concurrency:
group: clawhub-cli-npm-release-${{ inputs.tag }}
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
NODE_VERSION: "24.x"
BUN_VERSION: "1.3.10"
jobs:
preflight_clawhub_cli_npm:
if: ${{ inputs.preflight_only }}
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Forbid preflight artifact promotion on validation-only runs
if: ${{ inputs.preflight_run_id != '' }}
run: |
echo "preflight_run_id is only valid for real publish runs."
exit 1
- name: Checkout
uses: actions/checkout@v6
with:
ref: refs/tags/${{ inputs.tag }}
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
registry-url: https://registry.npmjs.org
- name: Setup Bun
uses: oven-sh/setup-bun@e3914758a49697077f7bcd190d36582a61667aad
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Resolve CLI package directory
run: |
set -euo pipefail
if [[ -d "packages/clawhub" ]]; then
echo "PACKAGE_DIR=packages/clawhub" >> "$GITHUB_ENV"
elif [[ -d "packages/clawdhub" ]]; then
echo "PACKAGE_DIR=packages/clawdhub" >> "$GITHUB_ENV"
else
echo "Unable to find clawhub CLI package directory." >&2
exit 1
fi
- name: Ensure version is not already published
env:
PREFLIGHT_ONLY: ${{ inputs.preflight_only }}
run: |
set -euo pipefail
PACKAGE_VERSION="$(node --input-type=module <<'EOF'
import { readFileSync } from "node:fs";
const pkg = JSON.parse(readFileSync(`./${process.env.PACKAGE_DIR}/package.json`, "utf8"));
process.stdout.write(String(pkg.version ?? "").trim());
EOF
)"
if npm view "clawhub@${PACKAGE_VERSION}" version >/dev/null 2>&1; then
if [[ "${PREFLIGHT_ONLY}" == "true" ]]; then
echo "clawhub@${PACKAGE_VERSION} is already published on npm; continuing because preflight_only=true."
exit 0
fi
echo "clawhub@${PACKAGE_VERSION} is already published on npm."
exit 1
fi
echo "Publishing clawhub@${PACKAGE_VERSION}"
- name: Validate release tag and package metadata
env:
RELEASE_TAG: ${{ inputs.tag }}
RELEASE_MAIN_REF: origin/main
run: |
set -euo pipefail
RELEASE_SHA="$(git rev-parse HEAD)"
export RELEASE_SHA
git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main
node scripts/clawhub-cli-npm-release-check.mjs
- name: Verify CLI package
run: bun run --cwd "$PACKAGE_DIR" verify
- name: Pack prepared npm tarball
id: packed_tarball
env:
RELEASE_TAG: ${{ inputs.tag }}
run: |
set -euo pipefail
pushd "$PACKAGE_DIR" >/dev/null
PACK_JSON="$(npm pack --json --ignore-scripts)"
echo "$PACK_JSON"
PACK_PATH="$(printf '%s\n' "$PACK_JSON" | node --input-type=module -e 'const chunks=[]; process.stdin.on("data", (chunk) => chunks.push(chunk)); process.stdin.on("end", () => { const parsed = JSON.parse(Buffer.concat(chunks).toString("utf8")); const first = Array.isArray(parsed) ? parsed[0] : null; if (!first || typeof first.filename !== "string" || !first.filename) process.exit(1); process.stdout.write(first.filename); });')"
popd >/dev/null
if [[ -z "${PACK_PATH}" || ! -f "${PACKAGE_DIR}/${PACK_PATH}" ]]; then
echo "npm pack did not produce a tarball file." >&2
exit 1
fi
RELEASE_SHA="$(git rev-parse HEAD)"
PACKAGE_VERSION="$(node --input-type=module <<'EOF'
import { readFileSync } from "node:fs";
const pkg = JSON.parse(readFileSync(`./${process.env.PACKAGE_DIR}/package.json`, "utf8"));
process.stdout.write(String(pkg.version ?? "").trim());
EOF
)"
ARTIFACT_DIR="$RUNNER_TEMP/clawhub-cli-npm-preflight"
rm -rf "$ARTIFACT_DIR"
mkdir -p "$ARTIFACT_DIR"
cp "${PACKAGE_DIR}/${PACK_PATH}" "$ARTIFACT_DIR/"
printf '%s\n' "$RELEASE_TAG" > "$ARTIFACT_DIR/release-tag.txt"
printf '%s\n' "$RELEASE_SHA" > "$ARTIFACT_DIR/release-sha.txt"
printf '%s\n' "$PACKAGE_VERSION" > "$ARTIFACT_DIR/package-version.txt"
echo "dir=$ARTIFACT_DIR" >> "$GITHUB_OUTPUT"
- name: Upload prepared npm publish bundle
uses: actions/upload-artifact@v7
with:
name: clawhub-cli-npm-preflight-${{ inputs.tag }}
path: ${{ steps.packed_tarball.outputs.dir }}
if-no-files-found: error
validate_publish_request:
if: ${{ !inputs.preflight_only }}
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Require main workflow ref for publish
env:
WORKFLOW_REF: ${{ github.ref }}
run: |
set -euo pipefail
if [[ "${WORKFLOW_REF}" != "refs/heads/main" ]]; then
echo "Real publish runs must be dispatched from main. Use preflight_only=true for branch validation."
exit 1
fi
- name: Require preflight artifact promotion on real publish
env:
PREFLIGHT_RUN_ID: ${{ inputs.preflight_run_id }}
run: |
set -euo pipefail
if [[ -z "${PREFLIGHT_RUN_ID}" ]]; then
echo "Real publish requires preflight_run_id from a successful npm preflight run." >&2
exit 1
fi
publish_clawhub_cli_npm:
needs: [validate_publish_request]
if: ${{ !inputs.preflight_only }}
runs-on: ubuntu-latest
environment: npm-release
permissions:
actions: read
contents: read
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: refs/tags/${{ inputs.tag }}
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
registry-url: https://registry.npmjs.org
- name: Resolve CLI package directory
run: |
set -euo pipefail
if [[ -d "packages/clawhub" ]]; then
echo "PACKAGE_DIR=packages/clawhub" >> "$GITHUB_ENV"
elif [[ -d "packages/clawdhub" ]]; then
echo "PACKAGE_DIR=packages/clawdhub" >> "$GITHUB_ENV"
else
echo "Unable to find clawhub CLI package directory." >&2
exit 1
fi
- name: Ensure version is not already published
run: |
set -euo pipefail
PACKAGE_VERSION="$(node --input-type=module <<'EOF'
import { readFileSync } from "node:fs";
const pkg = JSON.parse(readFileSync(`./${process.env.PACKAGE_DIR}/package.json`, "utf8"));
process.stdout.write(String(pkg.version ?? "").trim());
EOF
)"
if npm view "clawhub@${PACKAGE_VERSION}" version >/dev/null 2>&1; then
echo "clawhub@${PACKAGE_VERSION} is already published on npm."
exit 1
fi
echo "Publishing clawhub@${PACKAGE_VERSION}"
- name: Verify preflight run metadata
env:
GH_TOKEN: ${{ github.token }}
PREFLIGHT_RUN_ID: ${{ inputs.preflight_run_id }}
run: |
set -euo pipefail
RUN_JSON="$(gh run view "$PREFLIGHT_RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,headBranch,event,conclusion,url)"
printf '%s' "$RUN_JSON" | node --input-type=module -e 'const chunks=[]; process.stdin.on("data", (chunk) => chunks.push(chunk)); process.stdin.on("end", () => { const run = JSON.parse(Buffer.concat(chunks).toString("utf8")); const checks = [["workflowName", "ClawHub CLI NPM Release"], ["headBranch", "main"], ["event", "workflow_dispatch"], ["conclusion", "success"]]; for (const [key, expected] of checks) { if (run[key] !== expected) { console.error(`Referenced npm preflight run ${process.env.PREFLIGHT_RUN_ID} must have ${key}=${expected}, got ${run[key] ?? "<missing>"}.`); process.exit(1); } } console.log(`Using npm preflight run ${process.env.PREFLIGHT_RUN_ID}: ${run.url}`); });'
- name: Download prepared npm tarball
uses: actions/download-artifact@v8
with:
name: clawhub-cli-npm-preflight-${{ inputs.tag }}
path: preflight-tarball
repository: ${{ github.repository }}
run-id: ${{ inputs.preflight_run_id }}
github-token: ${{ github.token }}
- name: Validate release tag and package metadata
env:
RELEASE_TAG: ${{ inputs.tag }}
RELEASE_MAIN_REF: origin/main
run: |
set -euo pipefail
RELEASE_SHA="$(git rev-parse HEAD)"
export RELEASE_SHA
git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main
node scripts/clawhub-cli-npm-release-check.mjs
- name: Verify prepared tarball provenance
env:
RELEASE_TAG: ${{ inputs.tag }}
run: |
set -euo pipefail
EXPECTED_RELEASE_SHA="$(git rev-parse HEAD)"
EXPECTED_PACKAGE_VERSION="$(node --input-type=module <<'EOF'
import { readFileSync } from "node:fs";
const pkg = JSON.parse(readFileSync(`./${process.env.PACKAGE_DIR}/package.json`, "utf8"));
process.stdout.write(String(pkg.version ?? "").trim());
EOF
)"
TAG_FILE="preflight-tarball/release-tag.txt"
SHA_FILE="preflight-tarball/release-sha.txt"
VERSION_FILE="preflight-tarball/package-version.txt"
if [[ ! -f "$TAG_FILE" || ! -f "$SHA_FILE" || ! -f "$VERSION_FILE" ]]; then
echo "Prepared preflight metadata is missing." >&2
ls -la preflight-tarball >&2 || true
exit 1
fi
ARTIFACT_RELEASE_TAG="$(tr -d '\r\n' < "$TAG_FILE")"
ARTIFACT_RELEASE_SHA="$(tr -d '\r\n' < "$SHA_FILE")"
ARTIFACT_PACKAGE_VERSION="$(tr -d '\r\n' < "$VERSION_FILE")"
if [[ "$ARTIFACT_RELEASE_TAG" != "$RELEASE_TAG" ]]; then
echo "Prepared preflight tag mismatch: expected $RELEASE_TAG, got $ARTIFACT_RELEASE_TAG" >&2
exit 1
fi
if [[ "$ARTIFACT_RELEASE_SHA" != "$EXPECTED_RELEASE_SHA" ]]; then
echo "Prepared preflight SHA mismatch: expected $EXPECTED_RELEASE_SHA, got $ARTIFACT_RELEASE_SHA" >&2
exit 1
fi
if [[ "$ARTIFACT_PACKAGE_VERSION" != "$EXPECTED_PACKAGE_VERSION" ]]; then
echo "Prepared preflight package version mismatch: expected $EXPECTED_PACKAGE_VERSION, got $ARTIFACT_PACKAGE_VERSION" >&2
exit 1
fi
- name: Resolve publish tarball
id: publish_tarball
run: |
set -euo pipefail
TARBALL_PATH="$(find preflight-tarball -type f -name '*.tgz' -print | sort | tail -n 1)"
if [[ -z "$TARBALL_PATH" ]]; then
echo "Prepared preflight tarball not found." >&2
ls -la preflight-tarball >&2 || true
exit 1
fi
echo "path=$TARBALL_PATH" >> "$GITHUB_OUTPUT"
- name: Publish
run: |
set -euo pipefail
publish_target="${{ steps.publish_tarball.outputs.path }}"
if [[ -n "${publish_target}" ]]; then
publish_target="./${publish_target}"
fi
bash scripts/clawhub-cli-npm-publish.sh --publish "${publish_target}"
-176
View File
@@ -1,176 +0,0 @@
name: Deploy
on:
workflow_dispatch:
inputs:
target:
description: "What to deploy"
required: true
default: full
type: choice
options:
- full
- backend
- frontend
concurrency:
group: deploy-production
cancel-in-progress: true
jobs:
validate-deploy-request:
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
deploy_backend: ${{ steps.mode.outputs.deploy_backend }}
deploy_frontend: ${{ steps.mode.outputs.deploy_frontend }}
run_smoke: ${{ steps.mode.outputs.run_smoke }}
target: ${{ steps.mode.outputs.target }}
steps:
- name: Require main ref for production deploy
run: |
set -euo pipefail
if [[ "${GITHUB_REF}" != "refs/heads/main" ]]; then
echo "Production deploys must run from main."
exit 1
fi
- name: Resolve deploy mode
id: mode
run: |
set -euo pipefail
target="${{ inputs.target }}"
case "$target" in
full)
echo "deploy_backend=true" >> "$GITHUB_OUTPUT"
echo "deploy_frontend=true" >> "$GITHUB_OUTPUT"
echo "run_smoke=true" >> "$GITHUB_OUTPUT"
;;
backend)
echo "deploy_backend=true" >> "$GITHUB_OUTPUT"
echo "deploy_frontend=false" >> "$GITHUB_OUTPUT"
echo "run_smoke=true" >> "$GITHUB_OUTPUT"
;;
frontend)
echo "deploy_backend=false" >> "$GITHUB_OUTPUT"
echo "deploy_frontend=true" >> "$GITHUB_OUTPUT"
echo "run_smoke=true" >> "$GITHUB_OUTPUT"
;;
*)
echo "Unsupported deploy target: $target" >&2
exit 1
;;
esac
echo "target=$target" >> "$GITHUB_OUTPUT"
deploy-production:
runs-on: ubuntu-latest
timeout-minutes: 45
needs: validate-deploy-request
environment:
name: Production
url: https://clawhub.ai
env:
CONVEX_DEPLOY_KEY: ${{ secrets.CONVEX_DEPLOY_KEY }}
PLAYWRIGHT_AUTH_STORAGE_STATE_JSON: ${{ secrets.PLAYWRIGHT_AUTH_STORAGE_STATE_JSON }}
PLAYWRIGHT_BASE_URL: https://clawhub.ai
steps:
- name: Check deploy configuration
run: |
set -euo pipefail
missing=()
if [[ "${{ needs.validate-deploy-request.outputs.deploy_backend }}" == "true" && -z "$CONVEX_DEPLOY_KEY" ]]; then
missing+=("CONVEX_DEPLOY_KEY")
fi
if (( ${#missing[@]} > 0 )); then
echo "::error::Missing required production environment secrets: ${missing[*]}"
exit 1
fi
echo "Deploy target: ${{ needs.validate-deploy-request.outputs.target }}"
if [[ -z "$PLAYWRIGHT_AUTH_STORAGE_STATE_JSON" ]]; then
echo "PLAYWRIGHT_AUTH_STORAGE_STATE_JSON not set; authenticated smoke will be skipped."
fi
- 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
if: needs.validate-deploy-request.outputs.deploy_backend == 'true'
run: bunx convex env set APP_BUILD_SHA "${GITHUB_SHA}" --prod
- name: Stamp Convex deploy time
if: needs.validate-deploy-request.outputs.deploy_backend == 'true'
run: bunx convex env set APP_DEPLOYED_AT "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" --prod
- name: Deploy Convex
if: needs.validate-deploy-request.outputs.deploy_backend == 'true'
run: bun run convex:deploy
- name: Verify Convex contract
if: needs.validate-deploy-request.outputs.deploy_backend == 'true'
run: bun run verify:convex-contract -- --prod
- name: Wait for Vercel production deployment
if: needs.validate-deploy-request.outputs.deploy_frontend == 'true'
env:
GH_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_SHA: ${{ github.sha }}
VERCEL_STATUS_CONTEXT: Vercel clawhub
run: |
set -euo pipefail
for attempt in {1..90}; do
if ! state="$(gh api "repos/$GITHUB_REPOSITORY/commits/$GITHUB_SHA/status" \
--jq '.statuses[] | select(.context == env.VERCEL_STATUS_CONTEXT) | .state' \
2>/dev/null | head -n1)"; then
echo "GitHub status check failed for $GITHUB_SHA; retrying..."
sleep 10
continue
fi
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
- name: Install Playwright browser
if: needs.validate-deploy-request.outputs.run_smoke == 'true'
run: bunx playwright install --with-deps chromium
- name: Write authenticated storage state
if: needs.validate-deploy-request.outputs.run_smoke == 'true' && env.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
if: needs.validate-deploy-request.outputs.run_smoke == 'true'
run: bunx playwright test e2e/menu-smoke.pw.test.ts e2e/upload-auth-smoke.pw.test.ts
-341
View File
@@ -1,341 +0,0 @@
name: Package Publish
on:
workflow_call:
inputs:
source:
description: Package source to publish. Usually owner/repo, owner/repo@ref, or a GitHub URL.
required: false
type: string
default: ""
ref:
description: Optional ref to append to the source when source is not already pinned.
required: false
type: string
dry_run:
description: Preview only. When true, no publish mutation is performed.
required: false
type: boolean
default: true
json:
description: Emit structured JSON output.
required: false
type: boolean
default: true
registry:
description: ClawHub registry URL.
required: false
type: string
default: https://clawhub.ai
site:
description: ClawHub site URL.
required: false
type: string
default: https://clawhub.ai
owner:
description: Optional owner handle override for org/shared publishing.
required: false
type: string
version:
description: Optional package version override.
required: false
type: string
tags:
description: Optional comma-separated tags override.
required: false
type: string
default: latest
source_repo:
description: Optional source repo override for local-folder publishes.
required: false
type: string
source_commit:
description: Optional source commit override for local-folder publishes.
required: false
type: string
source_ref:
description: Optional source ref override for local-folder publishes.
required: false
type: string
clawhub_version:
description: Legacy npm CLI version input. Kept for compatibility; the workflow now runs the checked-out source.
required: false
type: string
default: latest
secrets:
clawhub_token:
required: false
outputs:
publish_json:
description: Structured JSON output from clawhub package publish.
value: ${{ jobs.publish.outputs.publish_json }}
release_id:
description: Published release id when dry_run is false.
value: ${{ jobs.publish.outputs.release_id }}
jobs:
publish:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
id-token: write
outputs:
publish_json: ${{ steps.capture.outputs.publish_json }}
release_id: ${{ steps.capture.outputs.release_id }}
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.sha }}
- uses: oven-sh/setup-bun@e3914758a49697077f7bcd190d36582a61667aad
with:
bun-version: 1.3.10
- name: Resolve ClawHub workflow source
id: clawhub_source
run: |
python3 - <<'PY'
import base64
import json
import os
from pathlib import Path
from urllib.request import Request, urlopen
request_token = os.environ.get("ACTIONS_ID_TOKEN_REQUEST_TOKEN", "").strip()
request_url = os.environ.get("ACTIONS_ID_TOKEN_REQUEST_URL", "").strip()
if not request_token or not request_url:
raise SystemExit("GitHub OIDC token request env vars are missing; id-token: write is required.")
audience = "clawhub-workflow-source"
joiner = "&" if "?" in request_url else "?"
token_url = f"{request_url}{joiner}audience={audience}"
request = Request(
token_url,
headers={"Authorization": f"Bearer {request_token}"},
)
with urlopen(request) as response:
payload = json.load(response)
token = str(payload.get("value", "")).strip()
if not token:
raise SystemExit("GitHub OIDC token response did not include a token value.")
try:
encoded_payload = token.split(".")[1]
except IndexError as exc:
raise SystemExit("GitHub OIDC token was not a valid JWT.") from exc
padding = "=" * (-len(encoded_payload) % 4)
claims = json.loads(
base64.urlsafe_b64decode(encoded_payload + padding).decode("utf-8")
)
workflow_ref = str(claims.get("job_workflow_ref", "")).strip()
workflow_sha = str(claims.get("job_workflow_sha", "")).strip()
repo, marker, _ = workflow_ref.partition("/.github/workflows/")
if not marker or not repo or not workflow_sha:
raise SystemExit(
"Unable to resolve reusable workflow source from GitHub OIDC claims: "
f"job_workflow_ref={workflow_ref!r} job_workflow_sha={workflow_sha!r}"
)
output_path = Path(os.environ["GITHUB_OUTPUT"])
with output_path.open("a", encoding="utf-8") as fh:
fh.write(f"repository={repo}\n")
fh.write(f"ref={workflow_sha}\n")
PY
- uses: actions/checkout@v6
with:
repository: ${{ steps.clawhub_source.outputs.repository }}
ref: ${{ steps.clawhub_source.outputs.ref }}
path: clawhub-source
- name: Install ClawHub CLI dependencies
working-directory: clawhub-source
run: bun install --frozen-lockfile
- name: Validate publish mode inputs
env:
DRY_RUN: ${{ inputs.dry_run }}
JSON_MODE: ${{ inputs.json }}
CLAWHUB_TOKEN: ${{ secrets.clawhub_token }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
run: |
if [[ "$JSON_MODE" != "true" ]]; then
echo "::warning::This reusable workflow always emits JSON output; forcing --json for downstream parsing."
fi
if [[ "$DRY_RUN" == "true" ]]; then
exit 0
fi
if [[ -n "$CLAWHUB_TOKEN" ]]; then
exit 0
fi
if [[ "$GITHUB_EVENT_NAME" == "workflow_dispatch" && -n "${ACTIONS_ID_TOKEN_REQUEST_URL:-}" && -n "${ACTIONS_ID_TOKEN_REQUEST_TOKEN:-}" ]]; then
echo "No ClawHub token provided; publish will rely on GitHub OIDC trusted publishing."
exit 0
fi
echo "::error::Real publishes need secrets.clawhub_token, or GitHub OIDC on workflow_dispatch runs (permissions.id-token=write)."
exit 1
- name: Write ClawHub config
env:
CLAWHUB_TOKEN: ${{ secrets.clawhub_token }}
CLAWHUB_REGISTRY: ${{ inputs.registry }}
run: |
if [[ -z "$CLAWHUB_TOKEN" ]]; then
echo "No ClawHub token provided, skipping config file creation."
exit 0
fi
python3 - <<'PY'
import json
import os
from pathlib import Path
path = Path(os.environ["RUNNER_TEMP"]) / "clawhub-config.json"
path.write_text(
json.dumps(
{
"registry": os.environ["CLAWHUB_REGISTRY"],
"token": os.environ["CLAWHUB_TOKEN"],
},
indent=2,
)
+ "\n",
encoding="utf-8",
)
print(path)
PY
echo "CLAWHUB_CONFIG_PATH=$RUNNER_TEMP/clawhub-config.json" >> "$GITHUB_ENV"
- name: Resolve publish command
env:
INPUT_SOURCE: ${{ inputs.source }}
INPUT_REF: ${{ inputs.ref }}
INPUT_DRY_RUN: ${{ inputs.dry_run }}
INPUT_OWNER: ${{ inputs.owner }}
INPUT_VERSION: ${{ inputs.version }}
INPUT_TAGS: ${{ inputs.tags }}
INPUT_SOURCE_REPO: ${{ inputs.source_repo }}
INPUT_SOURCE_COMMIT: ${{ inputs.source_commit }}
INPUT_SOURCE_REF: ${{ inputs.source_ref }}
INPUT_SITE: ${{ inputs.site }}
INPUT_REGISTRY: ${{ inputs.registry }}
CLAWHUB_TOKEN: ${{ secrets.clawhub_token }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
GITHUB_REPOSITORY: ${{ github.repository }}
GITHUB_REF: ${{ github.ref }}
GITHUB_SHA: ${{ github.sha }}
run: |
python3 - <<'PY'
import json
import os
import shlex
from pathlib import Path
source = os.environ["INPUT_SOURCE"].strip()
if not source:
source = os.environ["GITHUB_REPOSITORY"]
source_is_current_repo = source == os.environ["GITHUB_REPOSITORY"]
ref = os.environ["INPUT_REF"].strip()
if not ref and source_is_current_repo:
ref = os.environ["GITHUB_SHA"].strip()
is_local_source = source.startswith(".") or source.startswith("/") or Path(source).exists()
if ref and "@" not in source and not source.startswith("http") and not is_local_source:
source = f"{source}@{ref}"
cli_entry = (
Path(os.environ["GITHUB_WORKSPACE"])
/ "clawhub-source"
/ "packages"
/ "clawhub"
/ "src"
/ "cli.ts"
)
if not cli_entry.exists():
raise SystemExit(f"Missing ClawHub CLI entrypoint at {cli_entry}")
cmd = [
"bun",
str(cli_entry),
"package",
"publish",
source,
"--site",
os.environ["INPUT_SITE"],
"--registry",
os.environ["INPUT_REGISTRY"],
]
if os.environ["INPUT_DRY_RUN"] == "true":
cmd.append("--dry-run")
cmd.append("--json")
owner = os.environ["INPUT_OWNER"].strip()
version = os.environ["INPUT_VERSION"].strip()
tags = os.environ["INPUT_TAGS"].strip()
if owner:
cmd += ["--owner", owner]
if version:
cmd += ["--version", version]
if tags:
cmd += ["--tags", tags]
source_repo = os.environ["INPUT_SOURCE_REPO"].strip()
source_commit = os.environ["INPUT_SOURCE_COMMIT"].strip()
source_ref = os.environ["INPUT_SOURCE_REF"].strip()
if source_repo:
cmd += ["--source-repo", source_repo]
if source_commit:
cmd += ["--source-commit", source_commit]
if source_ref:
cmd += ["--source-ref", source_ref]
elif source_is_current_repo:
github_ref = os.environ["GITHUB_REF"].strip()
if github_ref:
cmd += ["--source-ref", github_ref]
if os.environ["INPUT_DRY_RUN"] != "true" and os.environ["CLAWHUB_TOKEN"].strip():
cmd += [
"--manual-override-reason",
f"GitHub Actions {os.environ['GITHUB_EVENT_NAME'].strip()} publish via CLAWHUB_TOKEN",
]
path = Path(os.environ["RUNNER_TEMP"]) / "clawhub-package-publish-command.sh"
shell_line = " ".join(shlex.quote(part) for part in cmd)
path.write_text("#!/usr/bin/env bash\nset -euo pipefail\n" + shell_line + "\n", encoding="utf-8")
path.chmod(0o755)
print(shell_line)
PY
- name: Run package publish
run: |
set -euo pipefail
"$RUNNER_TEMP/clawhub-package-publish-command.sh" | tee "$RUNNER_TEMP/package-publish.json"
- name: Capture workflow outputs
id: capture
run: |
python3 - <<'PY'
import json
import os
from pathlib import Path
output_path = Path(os.environ["RUNNER_TEMP"]) / "package-publish.json"
raw = output_path.read_text(encoding="utf-8").strip()
parsed = json.loads(raw)
github_output = Path(os.environ["GITHUB_OUTPUT"])
with github_output.open("a", encoding="utf-8") as fh:
fh.write("publish_json<<__CLAWHUB_JSON__\n")
fh.write(json.dumps(parsed, indent=2))
fh.write("\n__CLAWHUB_JSON__\n")
release_id = str(parsed.get("releaseId", "") or "")
fh.write(f"release_id={release_id}\n")
PY
- name: Upload publish JSON artifact
uses: actions/upload-artifact@v4
with:
name: clawhub-package-publish-json
path: ${{ runner.temp }}/package-publish.json
if-no-files-found: error
-64
View File
@@ -1,64 +0,0 @@
name: "Security Gate: Secret Scanning"
on:
push:
branches: ["**"]
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: Resolve scan range
id: scan_range
env:
EVENT_NAME: ${{ github.event_name }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PUSH_BASE_SHA: ${{ github.event.before }}
PUSH_HEAD_SHA: ${{ github.sha }}
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
run: |
set -euo pipefail
zero_sha="0000000000000000000000000000000000000000"
if [[ "$EVENT_NAME" == "pull_request" ]]; then
base="$PR_BASE_SHA"
head="$PR_HEAD_SHA"
else
base="$PUSH_BASE_SHA"
head="$PUSH_HEAD_SHA"
if [[ -z "$base" || "$base" == "$zero_sha" ]]; then
base="origin/$DEFAULT_BRANCH"
fi
fi
echo "base=$base" >> "$GITHUB_OUTPUT"
echo "head=$head" >> "$GITHUB_OUTPUT"
- 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: ${{ steps.scan_range.outputs.base }}
head: ${{ steps.scan_range.outputs.head }}
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
-30
View File
@@ -1,30 +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
convex/_generated/
skills-lock.json
*/skills/*
skills/*
-1
View File
@@ -1 +0,0 @@
22
-20
View File
@@ -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/",
],
}
-37
View File
@@ -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/"
]
}
-97
View File
@@ -1,97 +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/clawhub/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.
## Production Release
- Production deploys are manual-only. Merging to `main` does **not** deploy.
- To release production, start the GitHub Actions `Deploy` workflow from `main`:
`gh workflow run deploy.yml --repo openclaw/clawhub --ref main`
- The workflow supports `full`, `backend`, and `frontend` targets.
- `frontend` currently means: wait for the Vercel production deploy for the selected `main` SHA, then run production smoke checks. It does not call `vercel deploy` directly yet.
- The workflow uses the GitHub `Production` environment for deploy secrets, but it does not require a separate approval step.
- Prod deploy secrets live on the `Production` environment, not as ordinary repo secrets. Required: `CONVEX_DEPLOY_KEY`. Optional: `PLAYWRIGHT_AUTH_STORAGE_STATE_JSON`.
- CLI npm releases are also manual-only and tag-based. Stable tags only: `vX.Y.Z`. Start `ClawHub CLI NPM Release` from `main`, first with `preflight_only=true`, then rerun it with the same tag and the successful `preflight_run_id`.
- Real CLI publishes wait at the GitHub `npm-release` environment and use npm trusted publishing. Required npm trusted publisher settings: repository `openclaw/clawhub`, workflow `clawhub-cli-npm-release.yml`, environment `npm-release`.
## 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.
<!-- convex-ai-start -->
This project uses [Convex](https://convex.dev) as its backend.
When working on Convex code, **always read `convex/_generated/ai/guidelines.md` first** for important guidelines on how to correctly use Convex APIs and patterns. The file contains rules that override what you may have learned about Convex from training data.
Convex agent skills for common tasks can be installed by running `npx convex ai-files install`.
<!-- convex-ai-end -->
-414
View File
@@ -1,414 +0,0 @@
# Changelog
## 0.10.0 - 2026-04-05
### Added
- Design system: introduce a shared UI component library (`src/components/ui/`) built on Radix UI primitives — Button, Card, Badge, Tabs, Dialog, Input, Textarea, Label, Select, Avatar, Separator, Tooltip, ScrollArea, Sheet, Skeleton, and Table — following the shadcn/ui pattern with `cn()` + Tailwind utilities.
- Design system: `Button` supports `asChild` via Radix Slot for polymorphic rendering (e.g., wrapping `<Link>` without extra DOM).
- Layout: add `Container` component with `narrow` / `default` / `wide` size presets and `Breadcrumb` component for hierarchical navigation.
- Loading: add skeleton loading states (`SkillCardSkeleton`, `SkillDetailSkeleton`, `DashboardSkeleton`) replacing text-based "Loading..." indicators with animated placeholders.
- Errors: add `ErrorBoundary` with `resetKey` prop that auto-resets on route changes, wired into the root layout.
- Errors: surface fallback messages from Convex API error payloads in mutation/action error toasts.
- UX: add `EmptyState` component with icon, headline, description, and optional CTA action used across dashboard, stars, profile, and publish pages.
- UX: add confirmation dialogs for destructive skill ownership actions (transfer, abandon).
- Markdown: add `MarkdownPreview` component with `react-markdown`, `remark-gfm`, and `react-syntax-highlighter` for rich rendering of skill/plugin READMEs with syntax-highlighted code blocks, GFM tables, and task lists.
- Markdown: render tables with the new `Table` UI primitive for consistent styling across skill docs.
- Navigation: replace DropdownMenu-based mobile nav with a slide-out `Sheet` panel.
- Validation: add Zod schemas (`src/lib/schemas.ts`) for publish-skill, settings, report, and org forms.
- Management: restore capability-tags UI (crypto, requires-wallet, can-make-purchases, etc.) that was silently removed during the initial refactor.
- Management: add `.catch()` error handling with toast feedback on `setSoftDeleted` calls; prompt for hide/restore reasons.
### Changed
- CSS: migrate from a monolithic 5,161-line `styles.css` to Tailwind utilities on components, pruning CSS to ~1,000 lines (81% reduction). Dark mode now uses Tailwind `dark:` variants via a `@variant dark` directive bridging existing CSS custom properties.
- Tailwind: add `@theme` block mapping all CSS design tokens (`--bg`, `--surface`, `--ink`, `--accent`, `--line`, `--radius-*`, etc.) into first-class Tailwind utilities.
- Pages: modernize all route pages (home, skills browse, skill detail, dashboard, settings, publish-skill, publish-plugin, import, about, CLI auth, stars, souls, user profile, org profile, management, plugins browse, plugin detail) from CSS class selectors to Tailwind + UI primitives.
- Skills browse: widen container to `wide` (1400px) for better use of screen space on desktop; same for plugins browse.
- Skills browse: replace text-based filter toggles with pill chips and modernize toolbar layout.
- Skill detail: migrate tab controls from CSS-styled buttons to Radix `Tabs` primitive with proper `role="tab"` accessibility.
- Skill detail: replace inline CSS class-based install card with `SkillInstallCard` using Card + Button primitives.
- Header/Footer: migrate from CSS classes to Tailwind utilities with responsive Sheet-based mobile navigation.
- Dashboard: replace CSS table layout with `Table` UI primitive; add metric cards and skeleton loading.
- Settings: modernize form inputs with `Input`/`Textarea`/`Label` primitives and structured layout.
- Publish: use `Dialog` primitive for modals; inline validation indicators; modernized file list display.
### Fixed
- Auth: `EmptyState` "Sign in" button on publish page now triggers GitHub OAuth via `useAuthActions` instead of linking to non-existent `/signin` route.
- API: fix plugins page dev-mode `{"error":"Only HTML requests are supported here"}` by routing SSR and localhost API fetches directly to the Convex site URL instead of through TanStack Start's request pipeline.
- API: fix CORS error when `credentials: "include"` conflicts with `Access-Control-Allow-Origin: *` by making credentials conditional on same-origin requests.
- API: fix SSR `packageApiUrl` to always use `VITE_CONVEX_SITE_URL` directly, avoiding `getRequestUrl()` failures when SSR request context is unavailable.
- Management: restore `setSoftDeleted` reason parameter for hide/restore actions.
- Tests: rename `settings.test.tsx` to `-settings.test.tsx` to exclude from TanStack Router's file-based route discovery.
- Tests: add `@convex-dev/auth/react` mock for `useAuthActions` in upload route tests.
- Tests: update skill detail tests for Radix tab roles (`role="tab"` instead of `role="button"`), skeleton loading classes (`animate-pulse`), and capability tag data.
- Tests: update skills index tests for refreshed UI copy (placeholder text, empty state wording, loading indicator patterns).
- Tests: update SkillDiffCard tests for Tailwind active-tab class (`shadow-sm` replacing `.is-active`).
- Tests: update packages publish route tests for Tailwind border classes.
- Tests: update packageApi tests for conditional credentials and SSR URL resolution.
## 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.
-55
View File
@@ -1,55 +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).
## Production Release
- Production deploys are manual-only. Merging to `main` does **not** deploy.
- Start the GitHub Actions `Deploy` workflow from `main` with `gh workflow run deploy.yml --repo openclaw/clawhub --ref main`.
- The workflow supports `full`, `backend`, and `frontend` targets.
- `frontend` currently waits for the Vercel production deploy on the selected `main` SHA and then runs smoke checks. It does not trigger Vercel directly yet.
- The workflow uses the `Production` environment for deploy secrets, but it does not wait for a separate approval.
- Required prod secret: `CONVEX_DEPLOY_KEY` on the `Production` environment. Optional smoke secret: `PLAYWRIGHT_AUTH_STORAGE_STATE_JSON`.
- CLI npm releases are manual-only and tag-based through `ClawHub CLI NPM Release`. Stable tags only: `vX.Y.Z`. Run a `preflight_only=true` pass first, then rerun with the same tag plus `preflight_run_id` for the real publish.
- Real CLI publishes wait at `npm-release` and rely on npm trusted publishing for `openclaw/clawhub` + `clawhub-cli-npm-release.yml` + `npm-release`.
## 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.
<!-- convex-ai-start -->
This project uses [Convex](https://convex.dev) as its backend.
When working on Convex code, **always read `convex/_generated/ai/guidelines.md` first** for important guidelines on how to correctly use Convex APIs and patterns. The file contains rules that override what you may have learned about Convex from training data.
Convex agent skills for common tasks can be installed by running `npx convex ai-files install`.
<!-- convex-ai-end -->
-192
View File
@@ -1,192 +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/clawhub/`](packages/clawhub/). 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"
```
Use the package-local verification contract when working on the CLI:
```bash
bun run --cwd packages/clawhub test
bun run --cwd packages/clawhub verify:build
bun run --cwd packages/clawhub test:artifact
bun run --cwd packages/clawhub verify
```
`bun test packages/clawhub/` is not the supported workflow. Source tests and built-artifact smoke tests are intentionally split.
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
bun run --cwd packages/clawhub verify
```
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
-7
View File
@@ -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`.
-356
View File
@@ -1,356 +0,0 @@
# ClawHub Design System
This document outlines the design rules, patterns, and guidelines for the ClawHub platform to ensure consistency, accessibility, and maintainability across all components.
---
## Color System
### Brand Palette (OpenClaw)
ClawHub uses a strict **3-5 color palette** based on the OpenClaw brand:
| Token | Light Mode | Dark Mode | Usage |
|-------|------------|-----------|-------|
| `--accent` | `#dc2626` | `#dc2626` | Primary actions, interactive elements, emphasis |
| `--accent-deep` | `#b91c1c` | `#ef4444` | Hover states, secondary emphasis |
| `--ink` | `#0a0a0a` | `#fafafa` | Primary text |
| `--ink-soft` | `#525252` | `#a1a1a1` | Secondary text, descriptions |
| `--surface` | `#ffffff` | `#121212` | Card backgrounds, elevated surfaces |
| `--bg` | `#fafafa` | `#0a0a0a` | Page background |
### Rules
1. **Never exceed 5 colors** without explicit design approval
2. **Never use purple/violet prominently** unless explicitly requested
3. **Always override text color** when changing background color to ensure contrast
4. **Use semantic tokens** (`--accent`, `--ink`, `--surface`) instead of raw colors
---
## Typography
### Font Stack
```css
--font-sans: 'Geist', system-ui, sans-serif;
--font-mono: 'Geist Mono', monospace;
--font-display: 'Geist', system-ui, sans-serif;
```
### Scale
| Token | Size | Usage |
|-------|------|-------|
| `--fs-xs` | 0.75rem (12px) | Labels, badges, metadata |
| `--fs-sm` | 0.875rem (14px) | Body text, descriptions |
| `--fs-base` | 1rem (16px) | Default body text |
| `--fs-md` | 1.125rem (18px) | Subheadings |
| `--fs-lg` | 1.25rem (20px) | Section titles |
| `--fs-xl` | 1.5rem (24px) | Page headings |
### Rules
1. **Maximum 2 font families** per page
2. **Line height 1.4-1.6** for body text (use `leading-relaxed`)
3. **Never use decorative fonts** for body text
4. **Minimum font size: 14px** for readability
5. Use `text-balance` or `text-pretty` for titles
---
## Layout
### Method Priority
Use this hierarchy for layout decisions:
1. **Flexbox** - Default for most layouts
2. **CSS Grid** - Only for complex 2D layouts (cards, galleries)
3. **Never use floats** or absolute positioning unless absolutely necessary
### Spacing Scale
```css
--space-1: 0.25rem /* 4px */
--space-2: 0.5rem /* 8px */
--space-3: 0.75rem /* 12px */
--space-4: 1rem /* 16px */
--space-5: 1.5rem /* 24px */
--space-6: 2rem /* 32px */
```
### Grid Patterns
#### Auto-fit Grid (Recommended for Cards)
```css
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
```
- Automatically adjusts columns based on container width
- Prevents orphan items on partial rows
- Maintains consistent card widths
#### Fixed Grid (When exact columns needed)
```css
/* 3-column at desktop, 2 at tablet, 1 at mobile */
grid-template-columns: repeat(3, minmax(0, 1fr));
@media (max-width: 860px) {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (max-width: 520px) {
grid-template-columns: 1fr;
}
```
### Container Widths
| Size | Max Width | Usage |
|------|-----------|-------|
| Default | `--page-max` (1200px) | Standard pages |
| Narrow | `--page-narrow` (720px) | Reading content, forms |
| Wide | Full width | Dashboards, data tables |
---
## Components
### Cards
```css
.card {
padding: var(--space-4);
border: 1px solid var(--line);
border-radius: var(--r-md);
background: var(--surface);
}
```
**Rules:**
- Always use `display: flex; flex-direction: column;` for consistent height
- Add `flex: 1` to content area for equal-height cards in grids
- Include hover state with `border-color` and subtle `box-shadow`
### Buttons
| Variant | Usage |
|---------|-------|
| `primary` | Main actions (Submit, Save, Download) |
| `secondary` | Alternative actions |
| `ghost` | Tertiary actions, navigation |
| `destructive` | Delete, remove, dangerous actions |
**Rules:**
- Always include visible focus state
- Minimum touch target: 44x44px on mobile
- Include `aria-label` when icon-only
### Form Controls
- Labels above inputs (not inline)
- Error states use `--status-error-fg`
- Focus rings use `--accent` with 0.2 opacity
- Minimum input height: 40px
---
## Responsive Breakpoints
```css
/* Mobile first - base styles for mobile */
@media (min-width: 520px) {
/* Small tablets, large phones */
}
@media (min-width: 640px) {
/* Tablets */
}
@media (min-width: 860px) {
/* Small desktops, landscape tablets */
}
@media (min-width: 1024px) {
/* Desktops */
}
@media (min-width: 1280px) {
/* Large desktops */
}
```
### Rules
1. **Mobile-first approach** - Base styles target mobile
2. **Progressive enhancement** - Add complexity as viewport increases
3. **Test intermediate breakpoints** - Avoid jarring layout jumps
4. **Never hide critical content** on mobile
---
## Accessibility
### Color Contrast
- Normal text: Minimum 4.5:1 ratio
- Large text (18px+): Minimum 3:1 ratio
- Interactive elements: Minimum 3:1 ratio
### Focus States
```css
:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
border-radius: 2px;
}
```
### Screen Readers
- Use `sr-only` class for visually hidden but accessible text
- Always include `alt` text for images (empty `alt=""` for decorative)
- Use semantic HTML elements (`main`, `nav`, `article`, `section`)
- Proper heading hierarchy (h1 > h2 > h3, no skipping)
### Motion
```css
/* Respect user preference */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
```
---
## Animation
### Timing
```css
--transition-fast: 150ms;
--transition-base: 200ms;
--transition-slow: 300ms;
```
### Easing
- Use `ease` or `ease-out` for most transitions
- Use `ease-in-out` for enter/exit animations
- Never use `linear` except for continuous animations
### Rules
1. **Subtle by default** - Avoid flashy animations
2. **Purpose-driven** - Animation should provide feedback
3. **Respect preferences** - Support `prefers-reduced-motion`
4. **Performance** - Use `transform` and `opacity` only
---
## Icons
### Usage
- Use Lucide icons consistently
- Standard sizes: 14px, 16px, 20px, 24px
- Include `aria-hidden="true"` for decorative icons
- Never use emojis as icons
### Placement
- Left of labels in buttons and navigation
- Right of labels for external links or dropdowns
- Centered when used alone with `aria-label`
---
## Dark Mode
### Implementation
```css
[data-theme="dark"] {
/* Dark mode overrides */
}
```
### Rules
1. Never use pure white (`#ffffff`) on dark backgrounds
2. Reduce shadow intensity in dark mode
3. Adjust image brightness if needed
4. Test contrast ratios in both modes
---
## Performance
### CSS
1. Use CSS custom properties for theming
2. Avoid deeply nested selectors (max 3 levels)
3. Use `will-change` sparingly
4. Prefer `transform` over `top/left` for animations
### Images
1. Always specify `width` and `height` attributes
2. Use `loading="lazy"` for below-fold images
3. Use appropriate formats (WebP with fallbacks)
4. Include placeholder or skeleton states
---
## Code Style
### CSS Class Naming
```css
/* Component */
.component-name { }
/* Component modifier */
.component-name.variant { }
/* Component child */
.component-name-child { }
/* State */
.component-name.is-active { }
.component-name[data-state="open"] { }
```
### File Organization
```
src/
components/
ui/ # Primitive components (Button, Input, Card)
layout/ # Layout components (Container, Header)
styles.css # Global styles and design tokens
lib/
theme.ts # Theme utilities
preferences.ts # User preference management
```
---
## Checklist
Before shipping any UI changes, verify:
- [ ] Color contrast meets WCAG AA standards
- [ ] Focus states are visible
- [ ] Layout works at all breakpoints
- [ ] Animations respect `prefers-reduced-motion`
- [ ] Text is readable at default browser zoom
- [ ] Interactive elements have 44px minimum touch target
- [ ] Semantic HTML is used appropriately
- [ ] Dark mode has been tested
-21
View File
@@ -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.
-230
View File
@@ -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 skills: `clawhub skill publish <path>`, `clawhub sync`
- Publish plugins: `clawhub package publish <source>`
- 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
```
-98
View File
@@ -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.
-1643
View File
File diff suppressed because it is too large Load Diff
-49
View File
@@ -1,49 +0,0 @@
#!/usr/bin/env bun
import { existsSync } from 'node:fs'
import { stat } from 'node:fs/promises'
import { fileURLToPath } from 'node:url'
const packageRootPath = fileURLToPath(new URL('./packages/clawhub/', import.meta.url))
const distCliUrl = new URL('./packages/clawhub/dist/cli.js', import.meta.url)
const distCliPath = fileURLToPath(distCliUrl)
const srcRootPath = fileURLToPath(new URL('./packages/clawhub/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(['bun', 'run', 'build'], {
cwd: packageRootPath,
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 })) {
if (rel.endsWith('.test.ts')) continue
const path = `${root}${root.endsWith('/') ? '' : '/'}${rel}`
try {
const entry = await stat(path)
latest = Math.max(latest, entry.mtimeMs)
} catch {
// ignore
}
}
return latest
}
-49
View File
@@ -1,49 +0,0 @@
#!/usr/bin/env bun
import { existsSync } from 'node:fs'
import { stat } from 'node:fs/promises'
import { fileURLToPath } from 'node:url'
const packageRootPath = fileURLToPath(new URL('./packages/clawhub/', import.meta.url))
const distCliUrl = new URL('./packages/clawhub/dist/cli.js', import.meta.url)
const distCliPath = fileURLToPath(distCliUrl)
const srcRootPath = fileURLToPath(new URL('./packages/clawhub/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(['bun', 'run', 'build'], {
cwd: packageRootPath,
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 })) {
if (rel.endsWith('.test.ts')) continue
const path = `${root}${root.endsWith('/') ? '' : '/'}${rel}`
try {
const entry = await stat(path)
latest = Math.max(latest, entry.mtimeMs)
} catch {
// ignore
}
}
return latest
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 832 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 835 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

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"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

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"
}
Binary file not shown.

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"
}
]
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 593 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 KiB

Binary file not shown.

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"
}
]
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

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"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

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"
}
Binary file not shown.

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"
}
]
}
]
}
Binary file not shown.

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"
}
]
}
]
}
Binary file not shown.

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"
}
]
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

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"
}
]
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

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"
}
]
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

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"
}
]
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

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"
}
]
}
Binary file not shown.

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"
}
]
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

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"
}
]
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

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"
}
]
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 505 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 KiB

Some files were not shown because too many files have changed in this diff Show More