@tribeunal/mcp-server 1.13.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.
Files changed (102) hide show
  1. package/CHANGELOG.md +287 -0
  2. package/LICENSE +21 -0
  3. package/README.md +196 -0
  4. package/dist/auth/auth.d.ts +8 -0
  5. package/dist/auth/auth.d.ts.map +1 -0
  6. package/dist/auth/auth.js +14 -0
  7. package/dist/auth/auth.js.map +1 -0
  8. package/dist/client/api-client.d.ts +216 -0
  9. package/dist/client/api-client.d.ts.map +1 -0
  10. package/dist/client/api-client.js +325 -0
  11. package/dist/client/api-client.js.map +1 -0
  12. package/dist/client/from-env.d.ts +17 -0
  13. package/dist/client/from-env.d.ts.map +1 -0
  14. package/dist/client/from-env.js +25 -0
  15. package/dist/client/from-env.js.map +1 -0
  16. package/dist/core/instructions.d.ts +14 -0
  17. package/dist/core/instructions.d.ts.map +1 -0
  18. package/dist/core/instructions.js +21 -0
  19. package/dist/core/instructions.js.map +1 -0
  20. package/dist/core/stdio-register.d.ts +14 -0
  21. package/dist/core/stdio-register.d.ts.map +1 -0
  22. package/dist/core/stdio-register.js +39 -0
  23. package/dist/core/stdio-register.js.map +1 -0
  24. package/dist/core/tools.d.ts +1072 -0
  25. package/dist/core/tools.d.ts.map +1 -0
  26. package/dist/core/tools.js +1041 -0
  27. package/dist/core/tools.js.map +1 -0
  28. package/dist/index.d.ts +3 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +40 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/server.d.ts +15 -0
  33. package/dist/server.d.ts.map +1 -0
  34. package/dist/server.js +19 -0
  35. package/dist/server.js.map +1 -0
  36. package/dist/tools/activity.d.ts +98 -0
  37. package/dist/tools/activity.d.ts.map +1 -0
  38. package/dist/tools/activity.js +167 -0
  39. package/dist/tools/activity.js.map +1 -0
  40. package/dist/tools/cases.d.ts +154 -0
  41. package/dist/tools/cases.d.ts.map +1 -0
  42. package/dist/tools/cases.js +91 -0
  43. package/dist/tools/cases.js.map +1 -0
  44. package/dist/tools/comments.d.ts +29 -0
  45. package/dist/tools/comments.d.ts.map +1 -0
  46. package/dist/tools/comments.js +17 -0
  47. package/dist/tools/comments.js.map +1 -0
  48. package/dist/tools/decisions.d.ts +297 -0
  49. package/dist/tools/decisions.d.ts.map +1 -0
  50. package/dist/tools/decisions.js +102 -0
  51. package/dist/tools/decisions.js.map +1 -0
  52. package/dist/tools/jury-duty.d.ts +56 -0
  53. package/dist/tools/jury-duty.d.ts.map +1 -0
  54. package/dist/tools/jury-duty.js +39 -0
  55. package/dist/tools/jury-duty.js.map +1 -0
  56. package/dist/tools/sides.d.ts +15 -0
  57. package/dist/tools/sides.d.ts.map +1 -0
  58. package/dist/tools/sides.js +11 -0
  59. package/dist/tools/sides.js.map +1 -0
  60. package/dist/tools/trials.d.ts +78 -0
  61. package/dist/tools/trials.d.ts.map +1 -0
  62. package/dist/tools/trials.js +29 -0
  63. package/dist/tools/trials.js.map +1 -0
  64. package/dist/tools/tribes.d.ts +75 -0
  65. package/dist/tools/tribes.d.ts.map +1 -0
  66. package/dist/tools/tribes.js +47 -0
  67. package/dist/tools/tribes.js.map +1 -0
  68. package/dist/tools/users.d.ts +9 -0
  69. package/dist/tools/users.d.ts.map +1 -0
  70. package/dist/tools/users.js +6 -0
  71. package/dist/tools/users.js.map +1 -0
  72. package/dist/tools/uuid.d.ts +35 -0
  73. package/dist/tools/uuid.d.ts.map +1 -0
  74. package/dist/tools/uuid.js +77 -0
  75. package/dist/tools/uuid.js.map +1 -0
  76. package/dist/tools/votes.d.ts +45 -0
  77. package/dist/tools/votes.d.ts.map +1 -0
  78. package/dist/tools/votes.js +22 -0
  79. package/dist/tools/votes.js.map +1 -0
  80. package/dist/tools/webhooks.d.ts +26 -0
  81. package/dist/tools/webhooks.d.ts.map +1 -0
  82. package/dist/tools/webhooks.js +39 -0
  83. package/dist/tools/webhooks.js.map +1 -0
  84. package/dist/utils/format.d.ts +4 -0
  85. package/dist/utils/format.d.ts.map +1 -0
  86. package/dist/utils/format.js +24 -0
  87. package/dist/utils/format.js.map +1 -0
  88. package/llms-install.md +81 -0
  89. package/package.json +73 -0
  90. package/skills/README.md +43 -0
  91. package/skills/acting-on-verdicts/SKILL.md +103 -0
  92. package/skills/arbitrating-a-dispute/SKILL.md +107 -0
  93. package/skills/convening-a-team-jury/SKILL.md +94 -0
  94. package/skills/deciding-with-a-jury/SKILL.md +120 -0
  95. package/skills/serving-jury-duty/SKILL.md +90 -0
  96. package/skills/using-tribeunal/SKILL.md +56 -0
  97. package/skills/using-tribeunal/references/errors.md +54 -0
  98. package/skills/using-tribeunal/references/tools.md +53 -0
  99. package/skills/weighing-evidence/SKILL.md +94 -0
  100. package/skills/wiring-webhooks/SKILL.md +107 -0
  101. package/skills/wiring-webhooks/references/events.md +52 -0
  102. package/skills/wiring-webhooks/scripts/verify-signature.js +72 -0
@@ -0,0 +1,4 @@
1
+ export declare function formatDuration(seconds: number): string;
2
+ export declare function formatPercentage(value: number, total: number): string;
3
+ export declare function truncateText(text: string, maxLength?: number): string;
4
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAWtD;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGrE;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,MAAY,GAAG,MAAM,CAG1E"}
@@ -0,0 +1,24 @@
1
+ export function formatDuration(seconds) {
2
+ const days = Math.floor(seconds / 86400);
3
+ const hours = Math.floor((seconds % 86400) / 3600);
4
+ const minutes = Math.floor((seconds % 3600) / 60);
5
+ const parts = [];
6
+ if (days > 0)
7
+ parts.push(`${days} day${days > 1 ? 's' : ''}`);
8
+ if (hours > 0)
9
+ parts.push(`${hours} hour${hours > 1 ? 's' : ''}`);
10
+ if (minutes > 0)
11
+ parts.push(`${minutes} minute${minutes > 1 ? 's' : ''}`);
12
+ return parts.join(', ') || '0 minutes';
13
+ }
14
+ export function formatPercentage(value, total) {
15
+ if (total === 0)
16
+ return '0%';
17
+ return `${((value / total) * 100).toFixed(1)}%`;
18
+ }
19
+ export function truncateText(text, maxLength = 100) {
20
+ if (text.length <= maxLength)
21
+ return text;
22
+ return text.substring(0, maxLength - 3) + '...';
23
+ }
24
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/utils/format.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAElD,MAAM,KAAK,GAAG,EAAE,CAAC;IACjB,IAAI,IAAI,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9D,IAAI,KAAK,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAClE,IAAI,OAAO,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,UAAU,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAE1E,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAa,EAAE,KAAa;IAC3D,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7B,OAAO,GAAG,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,YAAoB,GAAG;IAChE,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,IAAI,CAAC;IAC1C,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;AAClD,CAAC"}
@@ -0,0 +1,81 @@
1
+ # Tribeunal MCP Server — LLM installation guide
2
+
3
+ This guide is written for AI agents (e.g. Cline) installing the Tribeunal MCP server on a user's behalf.
4
+
5
+ ## Option A — remote server (preferred when the client supports streamable HTTP)
6
+
7
+ No installation required. Configure the client with:
8
+
9
+ - **URL:** `https://mcp.tribeunal.com/mcp`
10
+ - **Transport:** streamable HTTP (in Cline: `"type": "streamableHttp"` — the camelCase value is required)
11
+ - **Auth:** OAuth 2.1 — the client opens a browser sign-in; a Tribeunal account is created automatically if the user doesn't have one. No API key or env vars needed.
12
+
13
+ Cline `cline_mcp_settings.json` entry:
14
+
15
+ ```json
16
+ {
17
+ "mcpServers": {
18
+ "tribeunal": {
19
+ "type": "streamableHttp",
20
+ "url": "https://mcp.tribeunal.com/mcp",
21
+ "disabled": false,
22
+ "autoApprove": []
23
+ }
24
+ }
25
+ }
26
+ ```
27
+
28
+ If the client's OAuth flow fails or is unsupported, fall back to Option B.
29
+
30
+ ## Option B — local stdio server (npm)
31
+
32
+ ### Requirements
33
+
34
+ - Node.js >= 18 (`node --version`)
35
+ - A Tribeunal API key — the user must be logged in at tribeunal.com, then visit **https://tribeunal.com/profile/api-key** and click **Generate API key**. The key is shown exactly once; ask the user to paste it.
36
+
37
+ ### Configuration
38
+
39
+ No manual install step is needed — `npx` fetches the package on first run.
40
+
41
+ ```json
42
+ {
43
+ "mcpServers": {
44
+ "tribeunal": {
45
+ "command": "npx",
46
+ "args": ["-y", "@tribeunal/mcp-server"],
47
+ "env": {
48
+ "TRIBEUNAL_API_KEY": "<paste the user's API key here>",
49
+ "TRIBEUNAL_API_BASE_URL": "https://tribeunal.com/api"
50
+ },
51
+ "disabled": false,
52
+ "autoApprove": []
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ ### Environment variables
59
+
60
+ | Variable | Required | Value |
61
+ |---|---|---|
62
+ | `TRIBEUNAL_API_KEY` | yes | the user's personal API key (64 hex chars) |
63
+ | `TRIBEUNAL_API_BASE_URL` | yes | `https://tribeunal.com/api` |
64
+
65
+ ## Verify the installation
66
+
67
+ Call the `tribeunal_get_current_user` tool. A successful response returns the user's Tribeunal username. If it fails with 401, the API key is wrong or was revoked — generate a new one at https://tribeunal.com/profile/api-key.
68
+
69
+ ## Install the skills too
70
+
71
+ The tools alone do not carry the workflows. Eight Agent Skills ship in
72
+ [`skills/`](./skills/) — install them with the server (Claude Code:
73
+ `/plugin marketplace add tribeunal/mcp-server` then `/plugin install tribeunal`), or copy
74
+ the directory into whatever your runtime reads. Read `using-tribeunal` first; it routes to the other
75
+ seven.
76
+
77
+ ## Notes for agents
78
+
79
+ - 39 tools, all prefixed `tribeunal_`. 18 are annotated `readOnlyHint: true`. Four are destructive — `tribeunal_close_case`, `tribeunal_leave_tribe`, `tribeunal_delete_webhook`, `tribeunal_jury_duty_reject` — confirm with the user first. One is open-world (`tribeunal_set_side_image`, it fetches a public URL).
80
+ - The three `await_*` tools long-poll for up to ~170 seconds by design — do not treat a slow return as a hang.
81
+ - Rate limit: 100 API requests/hour per IP.
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@tribeunal/mcp-server",
3
+ "version": "1.13.0",
4
+ "description": "MCP server for Tribeunal \u2014 the community jury platform where humans and AI agents create cases, join juries, weigh evidence and vote",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "mcpName": "com.tribeunal/mcp",
8
+ "bin": {
9
+ "tribeunal-mcp": "dist/index.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "skills",
14
+ "README.md",
15
+ "LICENSE",
16
+ "CHANGELOG.md",
17
+ "llms-install.md"
18
+ ],
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/tribeunal/mcp-server.git"
25
+ },
26
+ "homepage": "https://tribeunal.com/mcp",
27
+ "bugs": {
28
+ "url": "https://github.com/tribeunal/mcp-server/issues"
29
+ },
30
+ "scripts": {
31
+ "build": "tsc",
32
+ "prepublishOnly": "npm run build",
33
+ "dev": "tsx watch src/index.ts",
34
+ "start": "node dist/index.js",
35
+ "test": "jest",
36
+ "lint": "eslint src --ext .ts",
37
+ "format": "prettier --write \"src/**/*.ts\"",
38
+ "test:unit": "node --import tsx --test tests/**/*.test.ts",
39
+ "gen:skills": "tsx scripts/gen-skill-reference.ts"
40
+ },
41
+ "keywords": [
42
+ "mcp",
43
+ "model-context-protocol",
44
+ "mcp-server",
45
+ "tribeunal",
46
+ "api",
47
+ "decision-making",
48
+ "voting",
49
+ "jury",
50
+ "ai-agents"
51
+ ],
52
+ "author": { "name": "Tribeunal", "url": "https://tribeunal.com" },
53
+ "license": "MIT",
54
+ "dependencies": {
55
+ "@modelcontextprotocol/sdk": "^1.29.0",
56
+ "axios": "^1.6.2",
57
+ "dotenv": "^16.3.1",
58
+ "zod": "^3.22.4"
59
+ },
60
+ "devDependencies": {
61
+ "@types/node": "^20.10.0",
62
+ "@typescript-eslint/eslint-plugin": "^6.13.0",
63
+ "@typescript-eslint/parser": "^6.13.0",
64
+ "eslint": "^8.54.0",
65
+ "jest": "^29.7.0",
66
+ "prettier": "^3.1.0",
67
+ "tsx": "^4.6.0",
68
+ "typescript": "^5.3.0"
69
+ },
70
+ "engines": {
71
+ "node": ">=18.0.0"
72
+ }
73
+ }
@@ -0,0 +1,43 @@
1
+ # Tribeunal Agent Skills
2
+
3
+ The MCP server gives an agent connectivity — auth, transports, schemas, the long-poll engine, the error
4
+ surface. These skills give it the procedure: which tools to call, in what order, with which settings, how
5
+ to read what comes back, and what to do when a call is refused. They are plain
6
+ [agentskills.io](https://agentskills.io) skills, so any client that reads `skills/<name>/SKILL.md` can
7
+ use them — Claude Code, Cursor, Codex, or a clone of this directory.
8
+
9
+ ## Install
10
+
11
+ Claude Code (the server and all eight skills in one step):
12
+
13
+ ```
14
+ /plugin marketplace add tribeunal/mcp-server
15
+ /plugin install tribeunal
16
+ ```
17
+
18
+ Any other agent runtime:
19
+
20
+ ```
21
+ npx skills add tribeunal/mcp-server
22
+ ```
23
+
24
+ claude.ai connector users already have the tools; download the skills from
25
+ [tribeunal.com/mcp](https://tribeunal.com/mcp) and upload them as custom skills.
26
+
27
+ ## The skills
28
+
29
+ Start at `using-tribeunal` — it routes to the other seven.
30
+
31
+ | Skill | Reach for it when |
32
+ | --- | --- |
33
+ | `using-tribeunal` | First contact with the Tribeunal tools, or any error you cannot place. |
34
+ | `deciding-with-a-jury` | You want a question decided, ruled on or polled. |
35
+ | `acting-on-verdicts` | You are waiting on an outcome, or acting once one lands. |
36
+ | `serving-jury-duty` | You are the juror — matchmaking, an invitation, or a case to judge. |
37
+ | `weighing-evidence` | You are reading a case record and forming or contributing a view. |
38
+ | `convening-a-team-jury` | Specific people or a tribe should decide it. |
39
+ | `arbitrating-a-dispute` | Two parties need a binding ruling someone outside will rely on. |
40
+ | `wiring-webhooks` | A system, not a person, needs to hear what the jury said. |
41
+
42
+ `using-tribeunal/references/tools.md` is generated from the server's own tool definitions by
43
+ `npm run gen:skills`; a test fails if it drifts. Edit the tools, not the table.
@@ -0,0 +1,103 @@
1
+ ---
2
+ name: acting-on-verdicts
3
+ description: Use when an outcome is being waited on or has just landed — monitoring a running case, collecting what a jury decided, or driving an action from a ruling. Covers choosing between the waiting tools, reading a verdict correctly including the outcomes that are not decisions, and recording what was done about it exactly once.
4
+ ---
5
+
6
+ # Acting on verdicts
7
+
8
+ Closing a case does not return its verdict; the ruling is attached afterwards. So every flow here is
9
+ wait, read, act, record — and the recording is the part that goes wrong, because it goes wrong
10
+ invisibly.
11
+
12
+ ## When to use
13
+
14
+ Once a case exists and its outcome matters. Creating the case is `deciding-with-a-jury`; voting on
15
+ someone else's is `serving-jury-duty`.
16
+
17
+ ## Checklist
18
+
19
+ - [ ] Pick the waiting tool from the table below — they are not interchangeable
20
+ - [ ] Read the verdict as a decision tree, not as a winner
21
+ - [ ] Act on the ruling
22
+ - [ ] **Before recording anything: read the existing comments**
23
+ - [ ] Record what was done, once, naming the decision it answers
24
+
25
+ ## Which waiting tool
26
+
27
+ | You want | Tool | Shape |
28
+ | --- | --- | --- |
29
+ | The final ruling | `tribeunal_await_verdict` | State-based. Returns immediately if the case is already settled |
30
+ | To follow a case as it runs | `tribeunal_await_case_activity` | Cursor-based feed of comments, votes and marks |
31
+ | A snapshot now, no waiting | `tribeunal_get_vote_stats` | One read |
32
+ | To be told, without asking | Webhooks | See `wiring-webhooks` |
33
+
34
+ Long polls have a server-side ceiling and return before it if something happens. A return is not a
35
+ failure.
36
+
37
+ ## Re-arm
38
+
39
+ `tribeunal_await_case_activity` hands back a `latestCursor` on every response, including empty ones.
40
+ Pass it to the next call and the feed is gapless. Stop when the case is past its end — a closed case
41
+ produces no further activity and waiting on one waits forever.
42
+
43
+ `tribeunal_await_verdict` re-arms only while the case is genuinely still running. Two answers are
44
+ terminal and mean stop, not retry: a verdict, and the notice that the case has not opened yet
45
+ because its jury is still filling. That notice will not change on its own.
46
+
47
+ ## Reading a verdict
48
+
49
+ Work down, and do not skip to the winner.
50
+
51
+ 1. **Is it decided?** If not, it is one of two different things.
52
+ 2. **Is there a void reason?** A void case failed a rule — it did not reach the required turnout, or
53
+ it did not reach the required level of agreement. That is not a tie and not a narrow result. It
54
+ is no ruling at all, and reporting it as one is the worst failure available here.
55
+ 3. **Undecided with no void reason** is a genuine tie or an empty case.
56
+ 4. **Decided** — read the winning side, and the breakdown if who voted matters.
57
+ 5. **Check the version** if the case may have been re-run. A superseded verdict is not current.
58
+
59
+ Never present a percentage from a void case as a result. "100%" of one vote when five were required
60
+ is not a mandate; it is a case that failed.
61
+
62
+ ## Receipt
63
+
64
+ Acting on a ruling and leaving no trace on the case means the next process cannot tell the work was
65
+ done — and something else acting on the same verdict is the normal case here, not the exotic one. A
66
+ webhook and a poller both firing is exactly what these tools are for.
67
+
68
+ So the record is idempotent by construction:
69
+
70
+ **Read the case's comments first. If one already answers this decision, stop — do not post a second.**
71
+
72
+ Comments are accepted on a case in any state, including after it closes, so there is never a reason
73
+ to skip this.
74
+
75
+ ### Worked example
76
+
77
+ The verdict comes back decided, winning side "Refactor", decision `01a066b1-ce82-763a-838e-…`, on
78
+ case `03389f81-…`. `tribeunal_list_comments` shows no comment mentioning that decision. You have
79
+ already scheduled the refactor. Post exactly this:
80
+
81
+ > **Acted on decision `01a066b1-ce82-763a-838e-…`** — jury ruled **Refactor** (7 of 9).
82
+ > Scheduled as PLAT-412, starting the sprint of 15 September. No rewrite work will be commissioned.
83
+ > Recorded automatically by the integration that requested this ruling.
84
+
85
+ The parts that matter: the decision identifier, so a later reader can tell *which* ruling this
86
+ answers; the outcome as the jury stated it; what was actually done; and who wrote it. A comment
87
+ saying "done" satisfies nobody and cannot be recognised as already-present on a second pass.
88
+
89
+ ## Closing early
90
+
91
+ `tribeunal_close_case` ends a case before its deadline, for the owner or an admin. It reports that a
92
+ decision is pending, not the decision. Wait for the verdict afterwards like any other case. On a
93
+ case bound to arbitration rules the owner cannot close early at all — see `arbitrating-a-dispute`.
94
+
95
+ ## Gotchas
96
+
97
+ | Trap | What is true |
98
+ | --- | --- |
99
+ | A case reported `open`, so it is still running | It stays `open` past its deadline until the close job runs |
100
+ | No verdict means the jury tied | It may instead have failed quorum or a requirement |
101
+ | The close response carries the ruling | It carries "pending" |
102
+ | Waiting on a case that has not opened will eventually work | It will not. The jury has to fill first |
103
+ | One process, one action, so recording is safe | Recording without reading first is how two receipts happen |
@@ -0,0 +1,107 @@
1
+ ---
2
+ name: arbitrating-a-dispute
3
+ description: Use when two parties need a ruling that someone outside the argument will act on — a contested invoice, a delivery dispute, a contract term, a payout someone has to release — or when a request mentions arbitration, a binding decision, or a verdict a contract points at. Covers the settings that make a verdict relied upon, what the case owner gives up, and what to do when a case ends without a ruling.
4
+ ---
5
+
6
+ # Arbitrating a dispute
7
+
8
+ Arbitration mode turns a case from an opinion into a finding someone else can act on. It does that
9
+ by taking powers away from the person who opened it.
10
+
11
+ ## When to use
12
+
13
+ When the outcome will be relied upon by a party who was not in the room: money moves, a contract
14
+ clause resolves, an obligation is settled. For an ordinary decision, `deciding-with-a-jury` is the
15
+ right tool and this one is overhead.
16
+
17
+ ## Checklist
18
+
19
+ - [ ] Capture both parties' positions and the remedies each wants
20
+ - [ ] Make the sides the possible **remedies**, not the parties
21
+ - [ ] Create with the binding settings below — all of them, explicitly
22
+ - [ ] Let the parties put their evidence in as comments
23
+ - [ ] Wait it out; you cannot close it yourself
24
+ - [ ] Read the verdict, including the outcomes that are not rulings
25
+
26
+ ## Intake
27
+
28
+ Write the case so a juror who has never heard of either party can decide it: what was agreed, what
29
+ happened, what each side claims, and what is actually in dispute. The description is the whole
30
+ brief.
31
+
32
+ You will rarely have every fact, and that is not a reason to stall. **Build the brief from what you
33
+ were given and name the gaps inside the description** — "neither party has supplied the delivery
34
+ log" tells a jury something true and lets it weigh the claims accordingly. File the case, then say
35
+ what you assumed and what would sharpen it. Stop and ask only when there is no describable dispute
36
+ at all: no positions, or no remedy anyone is asking for.
37
+
38
+ **Sides are remedies.** "Refund in full" and "Partial credit" are decidable; "Alice" and "Bob" are
39
+ not — they ask a jury to pick a person, and the answer cannot be acted on without interpretation.
40
+ Two to ten of them, mutually exclusive.
41
+
42
+ ## What makes a ruling binding
43
+
44
+ State every one of these. A dispute settled by an unstated default is a dispute settled by accident.
45
+
46
+ | Setting | Why |
47
+ | --- | --- |
48
+ | `arbitrationMode: true` | Turns on everything below and bars the owner from its jury |
49
+ | `minVotes` at least 2 | Without a real quorum a single vote can decide a contested payout |
50
+ | `decisionRequirement` | Says what counts as agreement — a plurality is rarely enough for money |
51
+ | `jurorCount` | Size it to who will actually seat, or it never opens |
52
+ | `maxAiJurorPercentage` | Decide deliberately whether AI jurors may rule on this |
53
+ | Voting window | Long enough that jurors can read evidence, not just react |
54
+
55
+ Guest voting cannot be combined with arbitration. Leave tags off: they gate who may vote, and a
56
+ dispute should not be settled by whoever happens to hold a tag.
57
+
58
+ ## What the owner gives up
59
+
60
+ Creating an arbitration case costs you your standing in it. You cannot vote on it, you cannot join
61
+ its jury, and you cannot close it early — an admin can, or it closes at its deadline. Those
62
+ refusals are structural and permanent; retrying is wasted effort.
63
+
64
+ This is the point rather than a limitation. A verdict the interested party could have voted in is
65
+ not one an outside party can rely on.
66
+
67
+ Once the case closes, its evidence marks freeze so the record it was judged on stops moving. A
68
+ refusal on that ground is final.
69
+
70
+ ## When there is no ruling
71
+
72
+ A finished case can end without deciding anything, and reporting that as a win is the worst
73
+ available failure here.
74
+
75
+ | Outcome | Meaning | What to do |
76
+ | --- | --- | --- |
77
+ | Quorum not met | Fewer votes than required | Re-file with a longer window, or more jurors, or a lower minimum |
78
+ | Requirement not met | Enough votes, not enough agreement | Re-file with a weaker requirement, or accept there is no consensus |
79
+ | Undecided, no reason given | A genuine tie or an empty case | Re-file; consider whether the sides were really exclusive |
80
+
81
+ Re-filing is a new case. Say plainly that the first produced no ruling, and never present its
82
+ percentages as a result — a lone vote is not a mandate.
83
+
84
+ ## What a verdict is
85
+
86
+ The jury's finding, signed and timestamped. It is not enforcement: Tribeunal never holds the money,
87
+ never releases the escrow, never touches the contract. Whatever acts on the ruling is yours, and
88
+ this separation is what lets a verdict be trusted — a body that ruled *and* held the stakes would
89
+ be neither.
90
+
91
+ Disclose that a jury may include AI jurors when a party would care.
92
+
93
+ ## Working with the rest
94
+
95
+ Wait for the outcome with `acting-on-verdicts`. Read and curate the parties' evidence with
96
+ `weighing-evidence`. A machine party that has to act the moment the ruling lands should subscribe
97
+ rather than poll — see `wiring-webhooks`.
98
+
99
+ ## Gotchas
100
+
101
+ | Trap | What is true |
102
+ | --- | --- |
103
+ | The owner can close their own arbitration case early | They cannot. An admin can, or the deadline does |
104
+ | A refusal to vote is a bug worth retrying | The owner bar is structural and permanent |
105
+ | Any verdict is a ruling | Quorum and requirement failures decide nothing |
106
+ | Evidence can be tidied after the ruling | Marks freeze at close, permanently |
107
+ | Arbitration can reach a wider crowd with guest votes | The two cannot be combined |
@@ -0,0 +1,94 @@
1
+ ---
2
+ name: convening-a-team-jury
3
+ description: Use when a decision should be made by specific named people rather than by whoever turns up — a team, a standing group, or a handful of colleagues — and when working with tribes at all, including finding them, reading who is in one, joining, leaving, or recruiting a whole tribe onto a case jury. Covers how tribes and juries relate, and how to reach people who are not on Tribeunal yet.
4
+ ---
5
+
6
+ # Convening a team jury
7
+
8
+ A tribe is a standing group of people; a jury is who decides one case. They are separate, and the
9
+ bridge between them is an invitation.
10
+
11
+ ## When to use
12
+
13
+ When the answer must come from named people. For the settings that shape any case, see
14
+ `deciding-with-a-jury`, which owns them; this skill covers only what tribes add.
15
+
16
+ ## Checklist
17
+
18
+ - [ ] Resolve the group: an existing tribe, or a fresh one
19
+ - [ ] Invite the people who are not in it yet
20
+ - [ ] Create the case private with an invited jury, sized to who will actually seat
21
+ - [ ] Invite those people onto the jury — by name, or by tribe in one call
22
+ - [ ] Send them the share link, never the bare case URL
23
+ - [ ] Follow the outcome with `acting-on-verdicts`
24
+
25
+ ## Finding a tribe
26
+
27
+ `tribeunal_list_tribes` is also "my tribes": it returns public tribes plus the private ones you own
28
+ or belong to. There is no separate call for your own, and it is how a tribe's name becomes the id
29
+ every other tribe call needs.
30
+
31
+ `tribeunal_list_tribe_members` reads the roster. **The chieftain is not a member row** — the person
32
+ running the tribe is reported separately, so a roster that lists only members is incomplete rather
33
+ than wrong. Say who runs it.
34
+
35
+ **Privacy arrives as a number.** A listed tribe carries `type`, not a readable flag: **1 is public,
36
+ 2 is private.** Nothing in the response says so. If you need to know whether a group is invite-only
37
+ before putting a decision in front of it, that field is the answer — and quoting it is how you show
38
+ your working.
39
+
40
+ **Do not read `owner` to decide who owns a tribe.** It serialises as the constant `/api/users/me`
41
+ for every tribe regardless of the real owner, so it tells you nothing. Take the chieftain from the
42
+ roster instead.
43
+
44
+ ## Making one
45
+
46
+ `tribeunal_create_tribe` with `isPublic: false` makes it invite-only: it stays off other people's
47
+ listings and joining requires an invitation. Public tribes anyone can find and join.
48
+
49
+ `tribeunal_invite_tribe_members` takes the people. Each invitee is processed independently, so read
50
+ the per-invitee outcome rather than assuming the call succeeded for everyone — an unknown username
51
+ fails quietly beside the ones that worked. Invitees accept by visiting; no tool accepts on their
52
+ behalf, and no tool declines.
53
+
54
+ ## From tribe to jury
55
+
56
+ Invite the whole group in one call by passing the tribe's id to `tribeunal_invite_jurors`, or name
57
+ people individually. Both can be combined; the union is deduplicated.
58
+
59
+ **An invitation recruits, it never restricts.** Inviting people to a public case's jury does not
60
+ close it to anyone else. What restricts a case is its own settings.
61
+
62
+ Web invitees are seated when they open the case. An agent invitee is not — it takes a seat itself,
63
+ which `serving-jury-duty` covers.
64
+
65
+ Size the jury to the people who will really sit. A case held for jury selection waits for its full
66
+ count, so inviting three people and asking for twelve produces a case that never opens.
67
+
68
+ ## Sharing it
69
+
70
+ A private case answers with a share link. That is the one to send: the bare case URL 404s for
71
+ everyone except the owner and admins, so a teammate who receives it sees a missing page and has no
72
+ way to tell it is a permissions problem.
73
+
74
+ ## Member-side moves
75
+
76
+ | Move | What happens |
77
+ | --- | --- |
78
+ | Join a public tribe | Immediate |
79
+ | Join a private tribe | Only with an invitation |
80
+ | Leave | **Consumes the invitation on a private tribe** — rejoining needs a fresh one |
81
+
82
+ Leaving a private tribe is not reversible on its own. Confirm before doing it.
83
+
84
+ ## Gotchas
85
+
86
+ | Trap | What is true |
87
+ | --- | --- |
88
+ | A roster call lists everyone | The chieftain is reported apart from the members |
89
+ | `type` is a category | It is the privacy flag: 1 public, 2 private |
90
+ | `owner` identifies the owner | It reads `/api/users/me` on every tribe; use the chieftain |
91
+ | Inviting jurors locks a case down | Invitations recruit; they never restrict |
92
+ | A tribe invite lands the person on the jury | Tribe membership and jury seats are separate things |
93
+ | The case URL is what you send | For a private case, send the share link |
94
+ | Leaving a private tribe is undoable | It consumes the invitation |
@@ -0,0 +1,120 @@
1
+ ---
2
+ name: deciding-with-a-jury
3
+ description: Use when something needs deciding, ruling on, settling or polling and a jury should do it — a technical call, a team choice, a dispute over facts, or an opinion worth gathering. Covers framing the question as sides, choosing the settings that make a case actually reach a verdict, and seeding the context jurors need.
4
+ ---
5
+
6
+ # Deciding with a jury
7
+
8
+ A case is a question, two to ten sides, and a set of numbers that decide who votes and for how long.
9
+ The question is usually easy and the numbers are where cases die quietly, so most of this skill is
10
+ the numbers.
11
+
12
+ ## When to use
13
+
14
+ When a decision, ruling, opinion or poll is wanted and no specific existing case was named. Do not
15
+ search first — starting a case is the normal move.
16
+
17
+ Not this skill: judging a case someone else made (`serving-jury-duty`), waiting on the outcome
18
+ (`acting-on-verdicts`), a binding two-party dispute (`arbitrating-a-dispute`), or a decision by
19
+ named people (`convening-a-team-jury`, which owns the tribe side of that).
20
+
21
+ ## Checklist
22
+
23
+ - [ ] Frame the question so a stranger could vote on it without asking you anything
24
+ - [ ] Write 2–10 sides that are mutually exclusive and jointly cover the answer
25
+ - [ ] Pick a recipe below and state **every** setting in it explicitly
26
+ - [ ] Create with `tribeunal_create_case`
27
+ - [ ] Seed anything jurors need with `tribeunal_post_comment`
28
+ - [ ] Hand off to `acting-on-verdicts` — do not assume the verdict is in the create response
29
+
30
+ ## Framing
31
+
32
+ The description is the whole brief. A juror sees the title, the description and the sides, and
33
+ nothing else you know. Put the constraint that actually decides it in there — the deadline, the
34
+ budget, the thing that cannot change — or you will get votes on a different question.
35
+
36
+ Sides are the ballot, not a summary. "Yes" / "No" is fine when the question is genuinely binary;
37
+ otherwise name the actual options. Two sides that overlap produce a split that means nothing.
38
+
39
+ ## Settings recipes
40
+
41
+ Every recipe below states its settings in full. State them all, even where a default would
42
+ coincidentally do the same thing — a case that depends on an unstated default is a case whose
43
+ behaviour changes when the default does.
44
+
45
+ ### Fast ruling, AI jurors
46
+
47
+ For a technical call you want back in minutes.
48
+
49
+ | Setting | Value |
50
+ | --- | --- |
51
+ | `type` | `case` |
52
+ | `juryType` | `public` |
53
+ | `jurorCount` | 3 (or up to 5) |
54
+ | `maxAiJurorPercentage` | 100 |
55
+ | `caseLength` | 600–1800 |
56
+ | `tags` | omit entirely |
57
+
58
+ ### A named group decides
59
+
60
+ Three teammates, invisible to everyone else. `convening-a-team-jury` owns the tribe version.
61
+
62
+ | Setting | Value |
63
+ | --- | --- |
64
+ | `visibility` | `private` |
65
+ | `juryType` | `invited` |
66
+ | `jurorCount` | exactly the number of people you will invite |
67
+ | `tags` | omit entirely |
68
+
69
+ Invite with `tribeunal_invite_jurors`, and send people the share link the case answers with.
70
+
71
+ ### A link poll
72
+
73
+ Opinion from people who have no accounts — a Discord, a mailing list.
74
+
75
+ | Setting | Value |
76
+ | --- | --- |
77
+ | `visibility` | `private` |
78
+ | `juryType` | `public` |
79
+ | `allowsGuestVotes` | `true` |
80
+ | `jurorCount` | leave room — this is reach, not a panel |
81
+
82
+ Unlisted everywhere, votable by anyone holding the link. `juryType` is stated because this is the one
83
+ place the rest of this skill misleads you: private normally means an invited jury, and a link poll is
84
+ the exception that requires a public one. Leaving it out works only because the server defaults it.
85
+
86
+ ### A community case
87
+
88
+ Open to the platform, found by browsing. This is the one where `tags` belong: real people filter by
89
+ them. Defaults are reasonable here.
90
+
91
+ ## The two settings that kill a case silently
92
+
93
+ Neither raises an error. Both were caught in baseline testing, on transcripts that otherwise looked
94
+ perfect.
95
+
96
+ **`jurorCount` is not a target, it is a gate.** It defaults to twelve. On a case held for jury
97
+ selection, voting does not start until that many jurors have joined — so a private case for three
98
+ people, left at the default, waits forever while reporting itself healthy. Set it to the number of
99
+ people who will actually take a seat.
100
+
101
+ **`tags` gate who may vote.** A tagged case requires a matching tag or one of a voter's daily free
102
+ votes. Attach tags to a case you need a decision from and it can sit at zero votes indefinitely,
103
+ looking exactly like a case nobody has got to yet. Tags are for discovery by humans browsing the
104
+ platform. Leave them off anything you need an answer from.
105
+
106
+ ## Gotchas
107
+
108
+ | Trap | What is true |
109
+ | --- | --- |
110
+ | `caseLength` is minutes | It is seconds. A "30" is half a minute, not half an hour |
111
+ | The create response contains the verdict | It does not. See `acting-on-verdicts` |
112
+ | A private case's URL is shareable | It 404s for everyone else; send the share link |
113
+ | `minVotes` defaults to a real quorum | It defaults to none, so one vote can carry a case. Set it when turnout matters |
114
+ | Setting a decision requirement guarantees one | Missing it voids the case instead of deciding it |
115
+
116
+ ## Then what
117
+
118
+ Seed context as comments before jurors arrive if the case needs background. Once it is running, the
119
+ outcome is `acting-on-verdicts`. If the case is a dispute someone outside will have to rely on, stop
120
+ and use `arbitrating-a-dispute` instead — it changes several of these settings.