openclaw-productboard 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ /**
3
+ * Token Bucket Rate Limiter for ProductBoard API
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.RateLimiter = void 0;
7
+ exports.getRateLimiter = getRateLimiter;
8
+ exports.resetRateLimiter = resetRateLimiter;
9
+ const DEFAULT_OPTIONS = {
10
+ maxTokens: 100, // 100 requests
11
+ refillRate: 100, // Refill completely
12
+ refillInterval: 60 * 1000, // Per minute
13
+ };
14
+ class RateLimiter {
15
+ tokens;
16
+ lastRefill;
17
+ options;
18
+ constructor(options = {}) {
19
+ this.options = { ...DEFAULT_OPTIONS, ...options };
20
+ this.tokens = this.options.maxTokens;
21
+ this.lastRefill = Date.now();
22
+ }
23
+ /**
24
+ * Refill tokens based on elapsed time
25
+ */
26
+ refill() {
27
+ const now = Date.now();
28
+ const elapsed = now - this.lastRefill;
29
+ const intervals = Math.floor(elapsed / this.options.refillInterval);
30
+ if (intervals > 0) {
31
+ this.tokens = Math.min(this.options.maxTokens, this.tokens + intervals * this.options.refillRate);
32
+ this.lastRefill = now - (elapsed % this.options.refillInterval);
33
+ }
34
+ }
35
+ /**
36
+ * Try to acquire a token
37
+ * @returns true if token was acquired, false if rate limited
38
+ */
39
+ tryAcquire() {
40
+ this.refill();
41
+ if (this.tokens > 0) {
42
+ this.tokens--;
43
+ return true;
44
+ }
45
+ return false;
46
+ }
47
+ /**
48
+ * Acquire a token, waiting if necessary
49
+ * @returns Promise that resolves when a token is available
50
+ */
51
+ async acquire() {
52
+ if (this.tryAcquire()) {
53
+ return;
54
+ }
55
+ // Wait until next refill
56
+ const waitTime = this.getWaitTime();
57
+ await this.sleep(waitTime);
58
+ await this.acquire();
59
+ }
60
+ /**
61
+ * Get the time in milliseconds until a token is available
62
+ */
63
+ getWaitTime() {
64
+ this.refill();
65
+ if (this.tokens > 0) {
66
+ return 0;
67
+ }
68
+ const elapsed = Date.now() - this.lastRefill;
69
+ return this.options.refillInterval - elapsed;
70
+ }
71
+ /**
72
+ * Get current token count
73
+ */
74
+ getTokens() {
75
+ this.refill();
76
+ return this.tokens;
77
+ }
78
+ /**
79
+ * Reset the rate limiter to full capacity
80
+ */
81
+ reset() {
82
+ this.tokens = this.options.maxTokens;
83
+ this.lastRefill = Date.now();
84
+ }
85
+ /**
86
+ * Check if rate limited without consuming a token
87
+ */
88
+ isRateLimited() {
89
+ this.refill();
90
+ return this.tokens <= 0;
91
+ }
92
+ /**
93
+ * Get rate limiter statistics
94
+ */
95
+ stats() {
96
+ return {
97
+ tokens: this.getTokens(),
98
+ maxTokens: this.options.maxTokens,
99
+ waitTime: this.getWaitTime(),
100
+ };
101
+ }
102
+ sleep(ms) {
103
+ return new Promise((resolve) => setTimeout(resolve, ms));
104
+ }
105
+ }
106
+ exports.RateLimiter = RateLimiter;
107
+ // Singleton instance for the plugin
108
+ let rateLimiterInstance = null;
109
+ function getRateLimiter(options) {
110
+ if (!rateLimiterInstance) {
111
+ rateLimiterInstance = new RateLimiter(options);
112
+ }
113
+ return rateLimiterInstance;
114
+ }
115
+ function resetRateLimiter() {
116
+ rateLimiterInstance = null;
117
+ }
118
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmF0ZS1saW1pdGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWxzL3JhdGUtbGltaXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7O0dBRUc7OztBQW9JSCx3Q0FLQztBQUVELDRDQUVDO0FBbElELE1BQU0sZUFBZSxHQUF1QjtJQUMxQyxTQUFTLEVBQUUsR0FBRyxFQUFFLGVBQWU7SUFDL0IsVUFBVSxFQUFFLEdBQUcsRUFBRSxvQkFBb0I7SUFDckMsY0FBYyxFQUFFLEVBQUUsR0FBRyxJQUFJLEVBQUUsYUFBYTtDQUN6QyxDQUFDO0FBRUYsTUFBYSxXQUFXO0lBQ2QsTUFBTSxDQUFTO0lBQ2YsVUFBVSxDQUFTO0lBQ1YsT0FBTyxDQUFxQjtJQUU3QyxZQUFZLFVBQXVDLEVBQUU7UUFDbkQsSUFBSSxDQUFDLE9BQU8sR0FBRyxFQUFFLEdBQUcsZUFBZSxFQUFFLEdBQUcsT0FBTyxFQUFFLENBQUM7UUFDbEQsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQztRQUNyQyxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUMvQixDQUFDO0lBRUQ7O09BRUc7SUFDSyxNQUFNO1FBQ1osTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ3ZCLE1BQU0sT0FBTyxHQUFHLEdBQUcsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDO1FBQ3RDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDLENBQUM7UUFFcEUsSUFBSSxTQUFTLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDbEIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUNwQixJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsRUFDdEIsSUFBSSxDQUFDLE1BQU0sR0FB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cmQgQVBJXG4gKi9cblxuZXhwb3J0IGludGVyZmFjZSBSYXRlTGltaXRlck9wdGlvbnMge1xuICAvKiogTWF4aW11bSB0b2tlbnMgaW4gdGhlIGJ1Y2tldCAqL1xuICBtYXhUb2tlbnM6IG51bWJlcjtcbiAgLyoqIFRva2VucyBhZGRlZCBwZXIgaW50ZXJ2YWwgKi9cbiAgcmVmaWxsUmF0ZTogbnVtYmVyO1xuICAvKiogUmVmaWxsIGludGVydmFsIGluIG1pbGxpc2Vjb25kcyAqL1xuICByZWZpbGxJbnRlcnZhbDogbnVtYmVyO1xufVxuXG5jb25zdCBERUZBVUxUX09QVElPTlM6IFJhdGVMaW1pdGVyT3B0aW9ucyA9IHtcbiAgbWF4VG9rZW5zOiAxMDAsIC8vIDEwMCByZXF1ZXN0c1xuICByZWZpbGxSYXRlOiAxMDAsIC8vIFJlZmlsbCBjb21wbGV0ZWx5XG4gIHJlZmlsbEludGVydmFsOiA2MCAqIDEwMDAsIC8vIFBlciBtaW51dGVcbn07XG5cbmV4cG9ydCBjbGFzcyBSYXRlTGltaXRlciB7XG4gIHByaXZhdGUgdG9rZW5zOiBudW1iZXI7XG4gIHByaXZhdGUgbGFzdFJlZmlsbDogbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IG9wdGlvbnM6IFJhdGVMaW1pdGVyT3B0aW9ucztcblxuICBjb25zdHJ1Y3RvcihvcHRpb25zOiBQYXJ0aWFsPFJhdGVMaW1pdGVyT3B0aW9ucz4gPSB7fSkge1xuICAgIHRoaXMub3B0aW9ucyA9IHsgLi4uREVGQVVMVF9PUFRJT05TLCAuLi5vcHRpb25zIH07XG4gICAgdGhpcy50b2tlbnMgPSB0aGlzLm9wdGlvbnMubWF4VG9rZW5zO1xuICAgIHRoaXMubGFzdFJlZmlsbCA9IERhdGUubm93KCk7XG4gIH1cblxuICAvKipcbiAgICogUmVmaWxsIHRva2VucyBiYXNlZCBvbiBlbGFwc2VkIHRpbWVcbiAgICovXG4gIHByaXZhdGUgcmVmaWxsKCk6IHZvaWQge1xuICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gICAgY29uc3QgZWxhcHNlZCA9IG5vdyAtIHRoaXMubGFzdFJlZmlsbDtcbiAgICBjb25zdCBpbnRlcnZhbHMgPSBNYXRoLmZsb29yKGVsYXBzZWQgLyB0aGlzLm9wdGlvbnMucmVmaWxsSW50ZXJ2YWwpO1xuXG4gICAgaWYgKGludGVydmFscyA+IDApIHtcbiAgICAgIHRoaXMudG9rZW5zID0gTWF0aC5taW4oXG4gICAgICAgIHRoaXMub3B0aW9ucy5tYXhUb2tlbnMsXG4gICAgICAgIHRoaXMudG9rZW5zICsgaW50ZXJ2YWxzICogdGhpcy5vcHRpb25zLnJlZmlsbFJhdGVcbiAgICAgICk7XG4gICAgICB0aGlzLmxhc3RSZWZpbGwgPSBub3cgLSAoZWxhcHNlZCAlIHRoaXMub3B0aW9ucy5yZWZpbGxJbnRlcnZhbCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRyeSB0byBhY3F1aXJlIGEgdG9rZW5cbiAgICogQHJldHVybnMgdHJ1ZSBpZiB0b2tlbiB3YXMgYWNxdWlyZWQsIGZhbHNlIGlmIHJhdGUgbGltaXRlZFxuICAgKi9cbiAgdHJ5QWNxdWlyZSgpOiBib29sZWFuIHtcbiAgICB0aGlzLnJlZmlsbCgpO1xuXG4gICAgaWYgKHRoaXMudG9rZW5zID4gMCkge1xuICAgICAgdGhpcy50b2tlbnMtLTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBY3F1aXJlIGEgdG9rZW4sIHdhaXRpbmcgaWYgbmVjZXNzYXJ5XG4gICAqIEByZXR1cm5zIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIGEgdG9rZW4gaXMgYXZhaWxhYmxlXG4gICAqL1xuICBhc3luYyBhY3F1aXJlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLnRyeUFjcXVpcmUoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIFdhaXQgdW50aWwgbmV4dCByZWZpbGxcbiAgICBjb25zdCB3YWl0VGltZSA9IHRoaXMuZ2V0V2FpdFRpbWUoKTtcbiAgICBhd2FpdCB0aGlzLnNsZWVwKHdhaXRUaW1lKTtcbiAgICBhd2FpdCB0aGlzLmFjcXVpcmUoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIHRpbWUgaW4gbWlsbGlzZWNvbmRzIHVudGlsIGEgdG9rZW4gaXMgYXZhaWxhYmxlXG4gICAqL1xuICBnZXRXYWl0VGltZSgpOiBudW1iZXIge1xuICAgIHRoaXMucmVmaWxsKCk7XG5cbiAgICBpZiAodGhpcy50b2tlbnMgPiAwKSB7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG5cbiAgICBjb25zdCBlbGFwc2VkID0gRGF0ZS5ub3coKSAtIHRoaXMubGFzdFJlZmlsbDtcbiAgICByZXR1cm4gdGhpcy5vcHRpb25zLnJlZmlsbEludGVydmFsIC0gZWxhcHNlZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgY3VycmVudCB0b2tlbiBjb3VudFxuICAgKi9cbiAgZ2V0VG9rZW5zKCk6IG51bWJlciB7XG4gICAgdGhpcy5yZWZpbGwoKTtcbiAgICByZXR1cm4gdGhpcy50b2tlbnM7XG4gIH1cblxuICAvKipcbiAgICogUmVzZXQgdGhlIHJhdGUgbGltaXRlciB0byBmdWxsIGNhcGFjaXR5XG4gICAqL1xuICByZXNldCgpOiB2b2lkIHtcbiAgICB0aGlzLnRva2VucyA9IHRoaXMub3B0aW9ucy5tYXhUb2tlbnM7XG4gICAgdGhpcy5sYXN0UmVmaWxsID0gRGF0ZS5ub3coKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayBpZiByYXRlIGxpbWl0ZWQgd2l0aG91dCBjb25zdW1pbmcgYSB0b2tlblxuICAgKi9cbiAgaXNSYXRlTGltaXRlZCgpOiBib29sZWFuIHtcbiAgICB0aGlzLnJlZmlsbCgpO1xuICAgIHJldHVybiB0aGlzLnRva2VucyA8PSAwO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCByYXRlIGxpbWl0ZXIgc3RhdGlzdGljc1xuICAgKi9cbiAgc3RhdHMoKTogeyB0b2tlbnM6IG51bWJlcjsgbWF4VG9rZW5zOiBudW1iZXI7IHdhaXRUaW1lOiBudW1iZXIgfSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHRva2VuczogdGhpcy5nZXRUb2tlbnMoKSxcbiAgICAgIG1heFRva2VuczogdGhpcy5vcHRpb25zLm1heFRva2VucyxcbiAgICAgIHdhaXRUaW1lOiB0aGlzLmdldFdhaXRUaW1lKCksXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgc2xlZXAobXM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCBtcykpO1xuICB9XG59XG5cbi8vIFNpbmdsZXRvbiBpbnN0YW5jZSBmb3IgdGhlIHBsdWdpblxubGV0IHJhdGVMaW1pdGVySW5zdGFuY2U6IFJhdGVMaW1pdGVyIHwgbnVsbCA9IG51bGw7XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRSYXRlTGltaXRlcihvcHRpb25zPzogUGFydGlhbDxSYXRlTGltaXRlck9wdGlvbnM+KTogUmF0ZUxpbWl0ZXIge1xuICBpZiAoIXJhdGVMaW1pdGVySW5zdGFuY2UpIHtcbiAgICByYXRlTGltaXRlckluc3RhbmNlID0gbmV3IFJhdGVMaW1pdGVyKG9wdGlvbnMpO1xuICB9XG4gIHJldHVybiByYXRlTGltaXRlckluc3RhbmNlO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVzZXRSYXRlTGltaXRlcigpOiB2b2lkIHtcbiAgcmF0ZUxpbWl0ZXJJbnN0YW5jZSA9IG51bGw7XG59XG4iXX0=
@@ -0,0 +1,57 @@
1
+ {
2
+ "id": "productboard",
3
+ "name": "ProductBoard",
4
+ "version": "1.0.0",
5
+ "description": "ProductBoard integration for managing features, products, and customer feedback",
6
+ "configSchema": {
7
+ "type": "object",
8
+ "properties": {
9
+ "apiToken": {
10
+ "type": "string",
11
+ "description": "ProductBoard API bearer token"
12
+ },
13
+ "apiBaseUrl": {
14
+ "type": "string",
15
+ "default": "https://api.productboard.com",
16
+ "description": "ProductBoard API base URL"
17
+ },
18
+ "cacheTtlSeconds": {
19
+ "type": "number",
20
+ "default": 300,
21
+ "description": "Cache TTL in seconds for read operations"
22
+ },
23
+ "rateLimitPerMinute": {
24
+ "type": "number",
25
+ "default": 100,
26
+ "description": "Maximum API requests per minute"
27
+ }
28
+ },
29
+ "required": ["apiToken"]
30
+ },
31
+ "uiHints": {
32
+ "apiToken": {
33
+ "label": "ProductBoard API Token",
34
+ "placeholder": "pb_...",
35
+ "sensitive": true,
36
+ "helpText": "Get your API token from ProductBoard Settings > Integrations > Public API"
37
+ },
38
+ "apiBaseUrl": {
39
+ "label": "API Base URL",
40
+ "placeholder": "https://api.productboard.com",
41
+ "helpText": "Only change if using a custom ProductBoard instance"
42
+ },
43
+ "cacheTtlSeconds": {
44
+ "label": "Cache TTL (seconds)",
45
+ "helpText": "How long to cache read operations"
46
+ },
47
+ "rateLimitPerMinute": {
48
+ "label": "Rate Limit (requests/minute)",
49
+ "helpText": "Maximum API requests per minute"
50
+ }
51
+ },
52
+ "skills": [
53
+ "skills/productboard-search",
54
+ "skills/productboard-feedback",
55
+ "skills/productboard-release"
56
+ ]
57
+ }
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "openclaw-productboard",
3
+ "version": "1.0.0",
4
+ "description": "OpenClaw plugin for ProductBoard integration",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "openclaw": {
8
+ "extensions": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "clean": "rm -rf dist",
14
+ "prepublishOnly": "npm run build"
15
+ },
16
+ "keywords": [
17
+ "openclaw",
18
+ "productboard",
19
+ "plugin",
20
+ "product-management",
21
+ "agent-tools",
22
+ "api-integration"
23
+ ],
24
+ "author": "Roberto Moreno",
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/robertoamoreno/openclaw-productboard.git"
29
+ },
30
+ "homepage": "https://github.com/robertoamoreno/openclaw-productboard#readme",
31
+ "bugs": {
32
+ "url": "https://github.com/robertoamoreno/openclaw-productboard/issues"
33
+ },
34
+ "dependencies": {
35
+ "axios": "^1.6.0",
36
+ "lru-cache": "^10.0.1"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^20.0.0",
40
+ "typescript": "^5.3.0"
41
+ },
42
+ "engines": {
43
+ "node": ">=18.0.0"
44
+ },
45
+ "files": [
46
+ "dist",
47
+ "skills",
48
+ "openclaw.plugin.json",
49
+ "README.md",
50
+ "CHANGELOG.md",
51
+ "LICENSE"
52
+ ]
53
+ }
@@ -0,0 +1,105 @@
1
+ ---
2
+ name: productboard-feedback
3
+ description: Create and manage customer feedback notes in ProductBoard
4
+ user-invocable: true
5
+ ---
6
+
7
+ # ProductBoard Feedback Skill
8
+
9
+ Capture customer feedback, feature requests, and user insights in ProductBoard. Link feedback to features to aggregate customer evidence.
10
+
11
+ ## Available Tools
12
+
13
+ - `pb_note_create` - Create a new customer feedback note
14
+ - `pb_note_list` - List existing notes
15
+ - `pb_note_attach` - Link a note to a feature
16
+ - `pb_feature_search` - Find features to link notes to
17
+ - `pb_feature_list` - List features for context
18
+
19
+ ## Capturing Feedback
20
+
21
+ ### Creating Notes
22
+
23
+ Use `pb_note_create` with:
24
+
25
+ **Required**:
26
+ - `content` - The feedback text (supports HTML)
27
+
28
+ **Recommended**:
29
+ - `title` - Brief summary of the feedback
30
+ - `userEmail` - Who provided the feedback
31
+ - `userName` - User's name
32
+ - `companyName` - Their company/organization
33
+ - `tags` - Categories like "bug", "feature-request", "ux"
34
+
35
+ **Optional**:
36
+ - `displayUrl` - Link to original source (support ticket, Slack, etc.)
37
+ - `sourceOrigin` - System identifier (e.g., "zendesk", "intercom")
38
+ - `sourceRecordId` - ID in the source system
39
+
40
+ ### Linking to Features
41
+
42
+ 1. Find the relevant feature using `pb_feature_search` or `pb_feature_list`
43
+ 2. Use `pb_note_attach` with the `noteId` and `featureId`
44
+
45
+ ## Workflow Examples
46
+
47
+ ### Capture Support Ticket Feedback
48
+
49
+ ```
50
+ 1. pb_note_create:
51
+ - content: "User reports login takes too long on mobile devices"
52
+ - title: "Slow mobile login"
53
+ - userEmail: "customer@company.com"
54
+ - userName: "Jane Smith"
55
+ - companyName: "Acme Corp"
56
+ - tags: ["performance", "mobile", "authentication"]
57
+ - sourceOrigin: "zendesk"
58
+ - sourceRecordId: "12345"
59
+ - displayUrl: "https://zendesk.com/tickets/12345"
60
+
61
+ 2. pb_feature_search with query "mobile login" to find related feature
62
+
63
+ 3. pb_note_attach to link the note to the feature
64
+ ```
65
+
66
+ ### Capture Feature Request
67
+
68
+ ```
69
+ 1. pb_note_create:
70
+ - content: "Would love to have dark mode support in the app"
71
+ - title: "Dark mode request"
72
+ - userEmail: "user@example.com"
73
+ - tags: ["feature-request", "ui", "accessibility"]
74
+
75
+ 2. pb_feature_search with query "dark mode"
76
+
77
+ 3. If feature exists: pb_note_attach
78
+ If not: Consider creating feature with pb_feature_create
79
+ ```
80
+
81
+ ### Batch Feedback Processing
82
+
83
+ 1. Use `pb_note_list` to review recent unlinked notes
84
+ 2. For each note, search for relevant features
85
+ 3. Attach notes to appropriate features
86
+
87
+ ## Best Practices
88
+
89
+ - **Always include context**: Add user email, company, and source URL when available
90
+ - **Use consistent tags**: Establish a tagging convention (bug, feature-request, ux, performance, etc.)
91
+ - **Link to features**: Attached notes contribute to feature insights and prioritization
92
+ - **Keep titles concise**: Use title for quick scanning, content for details
93
+ - **Track the source**: Include sourceOrigin and sourceRecordId for traceability
94
+
95
+ ## Integration Points
96
+
97
+ - **Support Systems**: Zendesk, Intercom, Freshdesk
98
+ - **Communication**: Slack, Microsoft Teams, Email
99
+ - **Sales/CRM**: Salesforce, HubSpot, Pipedrive
100
+ - **User Research**: UserTesting, Hotjar, surveys
101
+
102
+ When capturing feedback from these systems, always include:
103
+ 1. The original source URL (displayUrl)
104
+ 2. The system name (sourceOrigin)
105
+ 3. The record ID (sourceRecordId)
@@ -0,0 +1,146 @@
1
+ ---
2
+ name: productboard-release
3
+ description: Manage ProductBoard releases and roadmap planning
4
+ user-invocable: false
5
+ metadata:
6
+ openclaw:
7
+ requires:
8
+ env:
9
+ - PRODUCTBOARD_API_TOKEN
10
+ ---
11
+
12
+ # ProductBoard Release Planning Skill
13
+
14
+ Plan and manage product releases by organizing features, tracking progress, and updating statuses in ProductBoard.
15
+
16
+ ## Available Tools
17
+
18
+ - `pb_feature_create` - Create new features for releases
19
+ - `pb_feature_update` - Update feature status and details
20
+ - `pb_feature_list` - List features by status or product
21
+ - `pb_feature_get` - Get detailed feature information
22
+ - `pb_product_list` - List products
23
+ - `pb_product_hierarchy` - View product structure
24
+ - `pb_user_list` - Find users to assign as owners
25
+
26
+ ## Release Planning Workflow
27
+
28
+ ### 1. Review Current State
29
+
30
+ ```
31
+ 1. pb_product_hierarchy - Understand workspace structure
32
+ 2. pb_feature_list with status "candidate" - Review feature candidates
33
+ 3. pb_feature_list with status "in-progress" - Check ongoing work
34
+ ```
35
+
36
+ ### 2. Prioritize Features
37
+
38
+ Review candidates and update their status:
39
+
40
+ ```
41
+ pb_feature_update:
42
+ - id: "feature-id"
43
+ - status: "in-progress" // Move to active development
44
+ ```
45
+
46
+ ### 3. Assign Owners
47
+
48
+ Find users and assign feature ownership:
49
+
50
+ ```
51
+ 1. pb_user_list - Get available team members
52
+ 2. pb_feature_update:
53
+ - id: "feature-id"
54
+ - ownerEmail: "developer@company.com"
55
+ ```
56
+
57
+ ### 4. Set Timeframes
58
+
59
+ Add planning dates to features:
60
+
61
+ ```
62
+ pb_feature_update:
63
+ - id: "feature-id"
64
+ - startDate: "2024-01-15"
65
+ - endDate: "2024-02-15"
66
+ ```
67
+
68
+ ### 5. Track Progress
69
+
70
+ Monitor feature statuses:
71
+
72
+ ```
73
+ pb_feature_list with status "in-progress" - Active development
74
+ pb_feature_list with status "shipped" - Completed features
75
+ ```
76
+
77
+ ## Feature Status Lifecycle
78
+
79
+ | Status | Description |
80
+ |--------|-------------|
81
+ | `new` | Just created, not yet evaluated |
82
+ | `candidate` | Being considered for development |
83
+ | `in-progress` | Actively being developed |
84
+ | `shipped` | Released to customers |
85
+ | `postponed` | Deferred to future planning |
86
+ | `archived` | No longer relevant |
87
+
88
+ ## Planning Scenarios
89
+
90
+ ### Sprint Planning
91
+
92
+ 1. List candidates: `pb_feature_list` with status "candidate"
93
+ 2. Review each feature: `pb_feature_get` for details
94
+ 3. Move selected features to in-progress: `pb_feature_update`
95
+ 4. Assign owners: `pb_feature_update` with ownerEmail
96
+ 5. Set sprint dates: `pb_feature_update` with startDate/endDate
97
+
98
+ ### Release Retrospective
99
+
100
+ 1. List shipped features: `pb_feature_list` with status "shipped"
101
+ 2. Review feedback on features: Use feedback skill tools
102
+ 3. Archive completed work: `pb_feature_update` with status "archived"
103
+
104
+ ### Quarterly Planning
105
+
106
+ 1. Review product hierarchy: `pb_product_hierarchy`
107
+ 2. List all active features by product
108
+ 3. Reassess priorities and update statuses
109
+ 4. Create new features as needed: `pb_feature_create`
110
+
111
+ ## Organizing Features
112
+
113
+ ### By Product
114
+
115
+ ```
116
+ pb_feature_create:
117
+ - name: "Feature name"
118
+ - productId: "product-id"
119
+ - status: "candidate"
120
+ ```
121
+
122
+ ### By Component
123
+
124
+ ```
125
+ pb_feature_create:
126
+ - name: "Feature name"
127
+ - componentId: "component-id"
128
+ - status: "candidate"
129
+ ```
130
+
131
+ ### As Sub-feature
132
+
133
+ ```
134
+ pb_feature_create:
135
+ - name: "Sub-feature name"
136
+ - parentFeatureId: "parent-feature-id"
137
+ ```
138
+
139
+ ## Best Practices
140
+
141
+ 1. **Use consistent statuses**: Move features through the lifecycle systematically
142
+ 2. **Assign owners early**: Clear ownership improves accountability
143
+ 3. **Set realistic timeframes**: Update dates as plans change
144
+ 4. **Organize hierarchically**: Use products, components, and sub-features
145
+ 5. **Archive completed work**: Keep the backlog clean by archiving shipped features
146
+ 6. **Review regularly**: Use listing tools to audit feature states
@@ -0,0 +1,62 @@
1
+ ---
2
+ name: productboard-search
3
+ description: Search and explore ProductBoard features, products, and feedback
4
+ user-invocable: true
5
+ ---
6
+
7
+ # ProductBoard Search Skill
8
+
9
+ Search and explore your ProductBoard workspace to find features, products, components, and customer feedback.
10
+
11
+ ## Available Tools
12
+
13
+ - `pb_search` - Global search across all ProductBoard entities
14
+ - `pb_feature_list` - List features with filters
15
+ - `pb_feature_get` - Get detailed feature information
16
+ - `pb_feature_search` - Search features by name/description
17
+ - `pb_product_list` - List all products
18
+ - `pb_product_get` - Get product details with components
19
+ - `pb_product_hierarchy` - View full product/component tree
20
+ - `pb_note_list` - List customer feedback notes
21
+
22
+ ## Search Strategies
23
+
24
+ ### Finding Features
25
+
26
+ 1. **By keyword**: Use `pb_feature_search` with a query term
27
+ 2. **By product**: Use `pb_feature_list` with `productId` filter
28
+ 3. **By status**: Use `pb_feature_list` with `status` filter (new, in-progress, shipped, archived)
29
+ 4. **By component**: Use `pb_feature_list` with `componentId` filter
30
+
31
+ ### Understanding Structure
32
+
33
+ 1. Start with `pb_product_hierarchy` to see the complete workspace organization
34
+ 2. Use `pb_product_get` to explore a specific product and its components
35
+ 3. Filter features by product or component to narrow down results
36
+
37
+ ### Finding Customer Feedback
38
+
39
+ 1. Use `pb_note_list` to see recent feedback
40
+ 2. Filter by date range using `createdFrom` and `createdTo`
41
+ 3. Use `pb_search` with type `note` to find specific feedback
42
+
43
+ ## Example Queries
44
+
45
+ **User**: "Find all features related to authentication"
46
+ **Action**: Use `pb_feature_search` with query "authentication"
47
+
48
+ **User**: "What features are currently in progress?"
49
+ **Action**: Use `pb_feature_list` with status "in-progress"
50
+
51
+ **User**: "Show me the product structure"
52
+ **Action**: Use `pb_product_hierarchy` to get the full tree
53
+
54
+ **User**: "Find customer feedback about performance"
55
+ **Action**: Use `pb_search` with query "performance" and type "note"
56
+
57
+ ## Tips
58
+
59
+ - Start broad with `pb_search`, then narrow down with specific tools
60
+ - Use `pb_product_hierarchy` first when exploring an unfamiliar workspace
61
+ - The search is case-insensitive and matches partial words
62
+ - Results include direct links to ProductBoard for quick access