@adrata/adrata-mcp 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.
Files changed (41) hide show
  1. package/README.md +548 -0
  2. package/access/auth.js +289 -0
  3. package/access/oauth.js +1059 -0
  4. package/access/resource-metadata.js +167 -0
  5. package/access/tiers.js +422 -0
  6. package/analytics.js +634 -0
  7. package/api-bridge.js +499 -0
  8. package/governance/money.js +141 -0
  9. package/output-formatter.js +589 -0
  10. package/package.json +68 -0
  11. package/resources.js +246 -0
  12. package/security.js +690 -0
  13. package/server.js +2139 -0
  14. package/server.json +55 -0
  15. package/skills/backlog-triage/SKILL.md +115 -0
  16. package/skills/board-review/SKILL.md +96 -0
  17. package/skills/incident-to-card/SKILL.md +126 -0
  18. package/skills/log-outreach.md +62 -0
  19. package/skills/ship-the-card/SKILL.md +155 -0
  20. package/tool-annotations.js +269 -0
  21. package/tools/billing.js +149 -0
  22. package/tools/email-tools.js +652 -0
  23. package/tools/enterprise-tools.js +651 -0
  24. package/tools/free-search.js +160 -0
  25. package/tools/memory.js +440 -0
  26. package/tools/morning-brief.js +551 -0
  27. package/tools/paper-tools.js +563 -0
  28. package/tools/scheduling.js +322 -0
  29. package/tools/work-board-tools.js +758 -0
  30. package/toolsets/communications.js +276 -0
  31. package/toolsets/crm.js +495 -0
  32. package/toolsets/extensibility.js +1131 -0
  33. package/toolsets/infrastructure.js +757 -0
  34. package/toolsets/intelligence.js +232 -0
  35. package/toolsets/knowledge.js +154 -0
  36. package/toolsets/matrix.js +217 -0
  37. package/toolsets/outreach.js +432 -0
  38. package/toolsets/prospecting.js +314 -0
  39. package/toolsets/revenue/always-loaded.js +341 -0
  40. package/toolsets/revenue/sloan-tools.js +81 -0
  41. package/transport-http.js +505 -0
package/server.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json",
3
+ "name": "com.adrata/adrata-mcp",
4
+ "description": "Adrata revenue-intelligence MCP server: companies, people, opportunities, actions, buyer groups, enrichment, email, and workspace operations for AI agents.",
5
+ "status": "active",
6
+ "version": "1.0.0",
7
+ "websiteUrl": "https://adrata.com/developers",
8
+ "repository": {
9
+ "url": "https://github.com/adrata/adrata",
10
+ "source": "github",
11
+ "subfolder": "code/mcp"
12
+ },
13
+ "packages": [
14
+ {
15
+ "registryType": "npm",
16
+ "registryBaseUrl": "https://registry.npmjs.org",
17
+ "identifier": "@adrata/adrata-mcp",
18
+ "version": "1.0.0",
19
+ "transport": {
20
+ "type": "stdio"
21
+ },
22
+ "environmentVariables": [
23
+ {
24
+ "name": "ADRATA_API_KEY",
25
+ "description": "Pro-tier API key. Omit for free tier; use OAuth (connect_workspace) for enterprise.",
26
+ "isRequired": false,
27
+ "isSecret": true
28
+ },
29
+ {
30
+ "name": "ADRATA_OAUTH_TOKEN",
31
+ "description": "Enterprise OAuth 2.1 access token, audience-bound to the Adrata MCP resource (RFC 8707).",
32
+ "isRequired": false,
33
+ "isSecret": true
34
+ }
35
+ ]
36
+ }
37
+ ],
38
+ "remotes": [
39
+ {
40
+ "type": "streamable-http",
41
+ "url": "https://mcp.adrata.com/mcp"
42
+ }
43
+ ],
44
+ "_meta": {
45
+ "com.adrata": {
46
+ "authorization": {
47
+ "spec": "MCP 2025-06-18",
48
+ "oauth": "2.1 + PKCE (S256)",
49
+ "resourceIndicators": "RFC 8707",
50
+ "protectedResourceMetadata": "RFC 9728 at /.well-known/oauth-protected-resource",
51
+ "tokenPassthrough": "rejected (audience-bound)"
52
+ }
53
+ }
54
+ }
55
+ }
@@ -0,0 +1,115 @@
1
+ ---
2
+ name: backlog-triage
3
+ description: Triage a Starfield backlog board — work the Triage column down, deduplicate against what is already there, tag by the board's own scheme, and route each card. Use when asked to triage, groom, sort, or "clean up" a backlog, or when someone asks what they should work on next.
4
+ ---
5
+
6
+ # Backlog triage
7
+
8
+ You are working someone's real backlog. Every move you make shows up on their
9
+ board on Monday morning, and a card you mis-tag is a card they stop trusting the
10
+ tag on. Be conservative and leave a trail.
11
+
12
+ ## Before you touch anything
13
+
14
+ 1. `list_work_boards` — get the board id. If there is more than one, ask which,
15
+ unless the request already names a company or product that identifies it.
16
+ 2. `get_work_board` — read the columns AND their staleness policies, and the
17
+ cards. Note the board's `tagScheme`: it decides the vocabulary you are
18
+ allowed to tag in.
19
+
20
+ **Read the whole board before changing one card.** Triage is a comparison
21
+ between cards, not a judgement on each in isolation — you cannot know a card is
22
+ a duplicate, or that it is the fifth report of one bug, without the rest.
23
+
24
+ ## The order of work
25
+
26
+ Work the board's FIRST column (usually Triage). Do not touch cards further
27
+ along: a card in In review has been looked at by someone who knew more than you
28
+ do about it.
29
+
30
+ For each card, in this order:
31
+
32
+ ### 1. Is it a duplicate?
33
+
34
+ Compare against every other card on the board, not just the same column. Two
35
+ cards are duplicates when fixing one closes the other — not merely when they use
36
+ similar words. "Export is slow" and "Export times out at 10k rows" may be one
37
+ bug or two; if you cannot tell, they are two.
38
+
39
+ Do NOT delete or merge duplicates on your own judgement. Say which cards you
40
+ believe are duplicates and why, and let a human collapse them. A wrongly merged
41
+ card loses its reporter and its evidence, and nobody ever notices.
42
+
43
+ ### 2. Is it actually a card?
44
+
45
+ Some Triage entries are questions, notifications, or half a thought. A card that
46
+ does not describe a change to make is not ready to be worked. Flag it, propose
47
+ a one-line rewrite that names the change, and leave it in Triage.
48
+
49
+ ### 3. Tag it
50
+
51
+ Use `set_work_item_tag` with the board's own `tagScheme`. Source is **`model`**
52
+ and you must give a `confidence` — you are a classifier here, not the person
53
+ whose call it is. Claiming `human` would launder your guess as their judgement.
54
+
55
+ Be conservative upward. The severity scheme's `critical` means *someone is
56
+ broken right now*: an outage, data loss, a security issue, or every customer
57
+ affected. A slow report is not critical. A backlog that cries wolf gets ignored,
58
+ and then the one real critical is missed.
59
+
60
+ If the card gives you no signal at all, leave it untagged rather than tagging it
61
+ low-confidence — the board falls back to its own deterministic rules, which is
62
+ more honest than a guess with a number on it.
63
+
64
+ ### 4. Route it
65
+
66
+ Move a card out of Triage only when you can say which column it belongs in and
67
+ why. `move_work_item`, with a `reason` that would satisfy the person who wrote
68
+ the card: "Reproduced on staging, needs a fix" beats "triaged".
69
+
70
+ The tool refuses a placeholder `reason` — "triaged", "moved", "update" — so the
71
+ line above is a rule the board now enforces rather than advice.
72
+
73
+ A card you could not tag confidently stays in Triage. That is the correct
74
+ outcome, not a failure.
75
+
76
+ ### 5. Leave the owner alone
77
+
78
+ Routing a card is not picking it up. Do **not** pass `claim` on these moves, and
79
+ never `force`: an assignee is how two people stay off one card, and triage
80
+ reassigning it is exactly the surprise that makes a board stop being trusted. A
81
+ card that already has an assignee is that person's — route it if it is in the
82
+ wrong column, and say so, but it stays theirs.
83
+
84
+ Picking work up is a different skill: `ship-the-card`.
85
+
86
+ ## What the ages mean
87
+
88
+ Every card carries `enteredColumnAt`. Compare it against **its own column's**
89
+ `agingAfterHours` / `staleAfterHours` — a missing bound means the column never
90
+ ages, which is what a Done column wants. Three days in Triage is alarming; three
91
+ days in In review is a Tuesday. Applying one threshold across the board will
92
+ make you report finished work as stale.
93
+
94
+ Stale cards in Triage are the ones to surface first: they have been waiting for
95
+ a decision nobody made.
96
+
97
+ ## Writes
98
+
99
+ Every move and tag change is a governed write. Preview first (the tools default
100
+ to `dryRun: true`), show the human the full list of what you intend to do, and
101
+ only then run with `dryRun: false`, `approved: true`, a `reason`, and an
102
+ `idempotencyKey`. Reuse the same key if you retry — a duplicate move makes the
103
+ card read as having bounced between columns, and the board's stage timer is
104
+ derived from exactly those rows.
105
+
106
+ ## What to report
107
+
108
+ A short list, in this shape:
109
+
110
+ - **Moved** — card, from → to, why.
111
+ - **Tagged** — card, tag, confidence, the signal you read it from.
112
+ - **Left in Triage** — card, and the specific question that would unblock it.
113
+ - **Possible duplicates** — the pairs, and what would confirm it.
114
+
115
+ No summary paragraph. The person reading this is about to act on it.
@@ -0,0 +1,96 @@
1
+ ---
2
+ name: board-review
3
+ description: Review a Starfield board or roll-up and report what is actually stuck — what has gone stale, what is unowned, where work is piling up, and which decisions are overdue. Use for a standup, a weekly review, a "how are we doing", or when someone asks what is blocked across their clients.
4
+ ---
5
+
6
+ # Board review
7
+
8
+ The question behind every board review is *what needs a decision that nobody is
9
+ making*. Card counts do not answer it. Time does.
10
+
11
+ ## Scope
12
+
13
+ - One team's board → `get_work_board`.
14
+ - Everything, across every client → `get_work_board_rollup` with `rollupId:
15
+ "all"`. This one has no membership rows, so it always includes a board created
16
+ five minutes ago.
17
+ - A curated view → `list_work_board_rollups`, then `get_work_board_rollup`.
18
+
19
+ A roll-up keeps provenance: every card still names its board and its company.
20
+ Use it. "Three cards are stale" is useless; "Acme has three stale cards, all in
21
+ Triage" is a conversation.
22
+
23
+ ## Read the time, not the count
24
+
25
+ Every card carries `enteredColumnAt`. Compare it against **its own column's**
26
+ policy — `agingAfterHours` and `staleAfterHours` live on the column, and a
27
+ missing bound means that column never ages.
28
+
29
+ This is the mistake to avoid: applying one threshold to a whole board. Three
30
+ days in Triage means nobody has decided. Three days in In review means it is
31
+ Tuesday. Three days in Done means nothing at all. A review that calls finished
32
+ work stale destroys its own credibility in one line.
33
+
34
+ On a roll-up, each slice carries the member board's own policy — use the slice's
35
+ policy for its own cards.
36
+
37
+ ## What to look for, in priority order
38
+
39
+ 1. **Stale in an early column.** A card sitting in Triage past its threshold is
40
+ a decision nobody made. This is the highest-value thing a review surfaces,
41
+ because it is pure latency — no work is happening and none is blocked on
42
+ anything real.
43
+
44
+ 2. **Work in progress with no assignee.** `assigneeUserId` absent on a card in
45
+ an active column means it is nobody's. Cards do not move themselves.
46
+ `list_my_work_items` with `includeUnassigned: true` returns the unowned pool
47
+ across every board directly, which is faster than scanning each board — but
48
+ its `assignedToMe` half answers only for YOU, so it is not a way to report on
49
+ anybody else's load. For that, read the boards and group by assignee.
50
+
51
+ 3. **A column piling up.** Compare column depths against the board's own
52
+ history, not against each other — some columns are meant to be deep. A
53
+ suddenly-deep In review means the reviewers are the bottleneck, not the
54
+ builders.
55
+
56
+ 4. **Critical cards that are not moving.** Cross the tag against the age. A card
57
+ tagged `critical` (or `p0`) that has been in one column for days is either
58
+ mis-tagged or genuinely on fire, and both are worth saying out loud. Use
59
+ `get_work_item_history` to see whether it has moved at all or has been
60
+ bouncing.
61
+
62
+ 5. **Cards that have bounced.** `get_work_item_history` shows every transition.
63
+ A card that has crossed the same boundary three times is not making progress;
64
+ it is missing information, and the history's `reason` fields usually say
65
+ which.
66
+
67
+ ## Do not equate tag schemes
68
+
69
+ Boards can use different vocabularies — severity, priority, kind, impact. A P1
70
+ is not a Critical, and nothing in this product will translate one into the
71
+ other. Rank within each board's own scheme and report them as they are. If you
72
+ need a single ordering across boards, say what you ordered by and that it is
73
+ your own reading, not the boards'.
74
+
75
+ ## This is a read-only skill
76
+
77
+ A review reports; it does not reorganise. If the review surfaces cards that
78
+ should move, say so and stop — moving them is `backlog-triage`, and it is a
79
+ separate decision the person may not want made for them. Do not call
80
+ `move_work_item` or `set_work_item_tag` here — and in particular do not claim a
81
+ card you noticed is unowned. Reviewing work and taking it are different acts, and
82
+ doing the second while asked for the first is how a review stops being safe to
83
+ ask for.
84
+
85
+ ## What to report
86
+
87
+ Lead with what is stuck, not with totals:
88
+
89
+ - **Overdue decisions** — card, board/company, how long it has waited, and the
90
+ specific question that would unstick it.
91
+ - **Unowned in-flight work** — card, board, column.
92
+ - **Bottleneck** — the column that is piling up, and against what.
93
+ - **Critical and not moving** — card, tag, days in column, whether it has moved.
94
+
95
+ Then, and only then, one line of totals. If nothing is stuck, say that plainly —
96
+ a clean board is a real result, and padding it with numbers hides it.
@@ -0,0 +1,126 @@
1
+ ---
2
+ name: incident-to-card
3
+ description: Turn a live problem — an alert, a failing build, a stack trace, a customer saying "it's down" — into a Starfield card that someone can actually pick up. Use when reporting a bug, filing an incident, or capturing something broken you found while working.
4
+ ---
5
+
6
+ # Incident to card
7
+
8
+ The gap between "I found a bug" and "someone fixed it" is almost always the
9
+ card. A card that says *Export broken* costs the next person an hour of
10
+ rediscovery. This skill is about spending two minutes now instead.
11
+
12
+ ## What makes a card workable
13
+
14
+ Five things, and a card missing any of them will bounce:
15
+
16
+ 1. **What you did** — the smallest sequence that shows the problem.
17
+ 2. **What happened** — the actual output. Paste the error, the status code, the
18
+ stack trace. Not your summary of it.
19
+ 3. **What you expected** — obvious to you, not to the person picking it up.
20
+ 4. **Where** — environment, build SHA or version, workspace/account if it is
21
+ scoped to one.
22
+ 5. **Acceptance criteria** — what would prove this fixed, as outcomes somebody
23
+ can check. See below; this is the one people leave off.
24
+
25
+ If you are filing from a conversation or a log you are looking at right now,
26
+ extract these from it. **Do not invent any of them.** A plausible repro that
27
+ does not reproduce is worse than no repro: it sends someone down a path you
28
+ never actually walked. If you do not know the expected behaviour, say "expected
29
+ unknown — reporter did not state it" in the body.
30
+
31
+ ## Acceptance criteria, and where they live
32
+
33
+ A card is the unit of QA sign-off: it is one judgement, made in one pass against
34
+ a written list. So every card carries that list, and post-AI it has **two**
35
+ readers — it is the build spec the agent works from and the test plan QA
36
+ validates against. The same sentences, doing both jobs. A card without them
37
+ makes the agent guess and gives QA nothing to check, which is how a card gets
38
+ signed off on the wrong thing.
39
+
40
+ **There is no acceptance-criteria field.** They live in the card's `body`, under
41
+ an `Acceptance criteria` heading, one checkable outcome per line:
42
+
43
+ ```
44
+ Acceptance criteria
45
+ - Exporting 10,000 rows completes without a 504.
46
+ - The export button is disabled until the download starts.
47
+ ```
48
+
49
+ Two rules that decide whether you have written them correctly:
50
+
51
+ - **One card is one QA judgement.** If your list needs QA to make more than one
52
+ call — "follows the OS theme" AND "the toggle persists" AND "every surface is
53
+ restyled" — that is several cards. A bounce from a multi-outcome card names
54
+ nothing actionable, which is what makes the second QA pass worthless. The
55
+ count is also the honest size signal: one line is a small card, five is a big
56
+ one, ten means you should have filed two.
57
+ - **Do not invent them**, on exactly the terms you do not invent a repro. If the
58
+ reporter never said what "fixed" looks like, write "acceptance criteria
59
+ unknown — reporter did not state what fixed looks like" and file it. That is a
60
+ triage problem for a human, and naming it is what gets it triaged; a made-up
61
+ criterion is worse, because QA will sign the card off against it.
62
+
63
+ Implementation steps are **not** criteria and never become their own cards:
64
+ "create a React hook", "rename the CSS variables" are lines in this body, in a
65
+ checklist under the criteria. There are deliberately no sub-tasks on this board.
66
+
67
+ ## Writing it
68
+
69
+ **Title**: the failure, not the area. `Checkout returns 500 for all customers
70
+ since the 14:02 deploy` — not `Checkout issue`. Someone scanning the board must
71
+ be able to tell whether this is theirs without opening it.
72
+
73
+ **Body**: the five things above, in that order, under plain headings. Keep the
74
+ raw error verbatim in a code block — the exact string is what someone will
75
+ grep for.
76
+
77
+ ## Filing it
78
+
79
+ 1. `list_work_boards` → pick the board. If the problem is scoped to a company
80
+ the workspace serves, use that company's board.
81
+ 2. `get_work_board` → find the Triage column (the first one) and read the
82
+ board's `tagScheme`.
83
+ 3. `create_work_item` with the title, the body, and `product` if you can tell
84
+ which one it belongs to.
85
+
86
+ **Leave `assigneeUserId` empty.** Filing a card is not picking it up, and an
87
+ assignee put on at filing time is a name nobody agreed to. An unowned card in the
88
+ first column is the honest state: it shows up in everybody's
89
+ `list_my_work_items` unassigned pool, which is where someone chooses to take it.
90
+ If you are going to work it yourself, file it unassigned and then claim it
91
+ properly — `ship-the-card`, one `move_work_item` with `claim: true`.
92
+
93
+ Filing it unassigned loses nothing, because **the card records who created it**
94
+ either way: the server stamps the creator from your authenticated session, so
95
+ the card can always be traced back to the person whose terminal it came from.
96
+ You cannot set it, and a body naming a creator is refused rather than ignored —
97
+ an author a tool could name would be a record of what the tool said, not of who
98
+ filed the card. Say "created by" and "assigned to" separately when you report
99
+ back; they are different people and the board keeps them apart.
100
+
101
+ Then tag it with `set_work_item_tag`, source `model` plus a `confidence`.
102
+
103
+ **The severity bar, if the board uses the severity scheme:** `critical` means
104
+ someone is broken right now — an outage, data loss, a security issue, or every
105
+ customer affected. A workaround existing usually means it is not critical. Be
106
+ honest about this even when the person reporting it is upset; the board's
107
+ credibility is what makes the next real critical get picked up fast.
108
+
109
+ If you are filing several cards from one incident, file the *symptom* people
110
+ hit, not one card per log line. Five cards for one root cause is five triage
111
+ decisions someone has to make.
112
+
113
+ ## Writes
114
+
115
+ `create_work_item` and `set_work_item_tag` are governed writes: they preview by
116
+ default. Show the human the card you are about to file — title, body, tag — and
117
+ file it only after they say yes, with `dryRun: false`, `approved: true`, a
118
+ `reason`, and an `idempotencyKey`. Reuse the same key on retry so a flaky
119
+ connection does not file the same incident twice.
120
+
121
+ ## After filing
122
+
123
+ Report the card id and its column. If you found something while filing that
124
+ suggests the cause — a recent deploy, a related card already on the board — say
125
+ so as a separate line, clearly marked as your inference rather than as evidence
126
+ from the report.
@@ -0,0 +1,62 @@
1
+ # Log Outreach Skill
2
+
3
+ Use the Adrata MCP to log sales outreach interactions. This skill replaces manual Airtable logging.
4
+
5
+ ## When to use
6
+
7
+ When the user says things like:
8
+ - "Log my LinkedIn outreach from today"
9
+ - "I sent a connection request to John Smith at Acme"
10
+ - "Log that I messaged these 5 people on LinkedIn"
11
+ - "Update my CRM with today's outreach"
12
+
13
+ ## How it works
14
+
15
+ Use the `log_interaction` tool for each interaction. It handles everything in one call:
16
+ 1. Finds the person by email or name (or creates them if new)
17
+ 2. Finds the company (or creates it if new)
18
+ 3. Creates an action with the interaction details and metadata
19
+ 4. Optionally updates the person's custom fields
20
+
21
+ ## Examples
22
+
23
+ ### Single interaction
24
+ ```
25
+ User: "I sent a LinkedIn connection request to Sarah Chen, VP Engineering at Dataflow Labs. Here's the message I sent: 'Hi Sarah, I noticed Dataflow is scaling their sales team...'"
26
+
27
+ → Call log_interaction with:
28
+ personName: "Sarah Chen"
29
+ companyName: "Dataflow Labs"
30
+ type: "linkedin_connection_request"
31
+ title: "Sent LinkedIn connection request to Sarah Chen"
32
+ message: "Hi Sarah, I noticed Dataflow is scaling their sales team..."
33
+ outcome: "pending"
34
+ ```
35
+
36
+ ### Batch logging
37
+ ```
38
+ User: "Log these LinkedIn messages I sent today:
39
+ 1. John Smith at Acme - connection request - 'Hi John...'
40
+ 2. Lisa Park at TechCorp - follow-up message - 'Thanks for connecting...'
41
+ 3. Mike Johnson at StartupXYZ - connection request - 'Hi Mike...'"
42
+
43
+ → Call log_interaction 3 times, once per person
44
+ ```
45
+
46
+ ### Connection accepted + meeting booked
47
+ ```
48
+ User: "Sarah Chen accepted my connection and we booked a meeting for Friday"
49
+
50
+ → Call log_interaction with:
51
+ personName: "Sarah Chen"
52
+ type: "meeting"
53
+ title: "Meeting booked with Sarah Chen"
54
+ outcome: "meeting_booked"
55
+ customFields: { "outreach_status": "meeting_scheduled" }
56
+ ```
57
+
58
+ ## Tips
59
+ - Always use `log_interaction` — it's the single tool that does find-or-create + action logging in one call
60
+ - For checking past outreach, use `list_actions` with type and person filters
61
+ - For "what did I do this week?", use `get_activity_summary`
62
+ - For finding specific people, use `search_people`
@@ -0,0 +1,155 @@
1
+ ---
2
+ name: ship-the-card
3
+ description: Take a Starfield card from its column through to a change that is ready for review — read the card and its history, do the work, and move it with a reason a human can audit. Use when asked to pick up a card, work the backlog, or "do the next thing" on a board.
4
+ ---
5
+
6
+ # Ship the card
7
+
8
+ This is the loop a coding agent actually runs: read a card, do the work, move
9
+ the card. The part people get wrong is the last step — work that lands with the
10
+ board untouched is work nobody can see.
11
+
12
+ ## Pick up
13
+
14
+ 1. `list_my_work_items` — **start here.** It answers "what is mine", across every
15
+ board, already ordered the way you would pick: escalated first, then the
16
+ board's own left-to-right flow, then longest-waiting. You do not have to pull
17
+ a board and eyeball it, and you cannot accidentally read somebody else's
18
+ queue — "me" comes from the token, and the tool has no parameter that could
19
+ name anyone else.
20
+ 2. If your queue is empty, call it again with `includeUnassigned: true`. Those
21
+ are the cards nobody owns, and they are the ones you may take. **A card
22
+ assigned to someone else is theirs** — do not work it, do not claim it. Say
23
+ you saw it if it is on fire, and leave it alone.
24
+ 3. `get_work_board` for the card's board when you need the target column id —
25
+ `move_work_item` moves to a column id, and only `get_work_board` has them.
26
+ 4. `get_work_item` for the full body, `get_work_item_history` for how it got
27
+ here, and `get_work_item_comments` for what people have SAID about it.
28
+ **Read both before starting.** A card that has bounced out of a review column
29
+ twice was rejected for a reason: the history says WHEN it bounced, the
30
+ comments say WHY. Repeating a rejected approach is the most expensive mistake
31
+ available here, and the reviewer's comment is usually the one thing that
32
+ would have stopped you.
33
+
34
+ **A card carrying a `flag` is not workable.** The flag means somebody has already
35
+ found a problem with the card ITSELF — unclear scope, no repro, a blocked
36
+ dependency, a question waiting on an answer — and its `reason` says which. It is
37
+ a different claim from the tag, which is only about urgency: a flagged Critical
38
+ card is still not something to start on. Read the comments for the surrounding
39
+ argument and pick a different card, unless you are the person who can answer it.
40
+ If you resolve it, clear the flag with `flag_work_item` (`flagged: false`) and
41
+ say what resolved it. Anyone may clear one, which is exactly why every clear is
42
+ recorded as a comment.
43
+
44
+ If the card is not workable — no repro, no expected behaviour, ambiguous scope —
45
+ **flag it** with `flag_work_item` and the one question that would unblock it,
46
+ then stop. Do not invent the missing half. Flagging is what turns "I could not
47
+ work this" into something the next person sees before they pick it up, rather
48
+ than a sentence in your report that nobody reads. An unworkable card is a triage
49
+ problem, not a coding problem.
50
+
51
+ ## Claim it, in the same move, FIRST
52
+
53
+ Before you write code, move the card to the board's active column **with
54
+ `claim: true`**. One call, not two:
55
+
56
+ ```
57
+ move_work_item(itemId, toColumnId: <the active column>, claim: true,
58
+ dryRun: false, approved: true,
59
+ reason: "Picked up — reproducing against staging first",
60
+ idempotencyKey: "claim-<itemId>")
61
+ ```
62
+
63
+ Three reasons, and the third is the real one:
64
+
65
+ - claiming stops someone else picking up the same card;
66
+ - moving it now starts the stage timer honestly. Moving it at the end backdates
67
+ the work to zero and quietly corrupts the board's cycle-time history;
68
+ - doing both in ONE call is what makes it true. A separate "assign" step is the
69
+ step that gets skipped, and a card sitting in an active column with nobody's
70
+ name on it is exactly what the board's unassigned glyph exists to shout about.
71
+
72
+ Reuse the same `idempotencyKey` if the call fails and you retry. The server
73
+ replays rather than appending a second transition.
74
+
75
+ **If the claim is refused**, the card already belongs to somebody: pick a
76
+ different one. `force: true` exists — it takes the card over and demands a reason
77
+ saying why — but it is for a card whose owner is genuinely gone, not for working
78
+ around a refusal. Taking someone's card because it was convenient is the one move
79
+ on this board that costs trust permanently. If you use it, say so in your report,
80
+ not only in the reason field.
81
+
82
+ ## Do the work
83
+
84
+ Ordinary engineering. Follow the repository's own conventions and its
85
+ `CLAUDE.md` / `AGENTS.md`. Nothing about this skill overrides the project's
86
+ rules — it only governs the board.
87
+
88
+ Two things to carry back to the card:
89
+
90
+ - if what you find contradicts the card, say so on the card rather than silently
91
+ fixing something else — `comment_on_work_item` is where that goes. A card that
92
+ says "export is slow" and turns out to be an auth timeout is a different card.
93
+ **Do not edit the card's body to make the point:** the body is the original
94
+ request, and overwriting it destroys the evidence of what was actually asked
95
+ for. A comment sits beside it and keeps both.
96
+ - if the comment needs a specific person's attention, @-mention them by writing
97
+ `<@userId>` in the body — the id comes from the card's assignee, its history,
98
+ or `list_my_work_items`. Writing `@noah` mentions nobody; that is deliberate,
99
+ so nothing you merely type can notify somebody by accident. Mention the person
100
+ who can answer, not everyone who might care: a mention means "see this" and
101
+ nothing else, and a thread that pings four people to reach one is how a team
102
+ learns to ignore them.
103
+ - if the fix is bigger than the card, do not quietly expand scope. Finish what
104
+ the card asked for and report the rest as a card that should exist. If you
105
+ file it yourself, file it the way `incident-to-card` says: a title, a body
106
+ carrying **acceptance criteria** — what would prove it done, one checkable
107
+ outcome per line — and no assignee. A card you file from here arrives
108
+ attributed to you automatically (the server stamps the creator from your
109
+ session), so the next person at aligning can ask you what you meant; what it
110
+ must not arrive with is a list of outcomes nobody can check.
111
+
112
+ ## Submit it
113
+
114
+ When the change is ready for review, `move_work_item` it onward — no `claim`
115
+ this time, you already own it — with a `reason` that carries something a human
116
+ can audit:
117
+
118
+ - a branch name, or
119
+ - a PR link, or
120
+ - one line naming what changed and how it was verified.
121
+
122
+ > "Fixed the N+1 in the export query on `fix/export-n1`; added a test at 10k
123
+ > rows, full suite green."
124
+
125
+ That reason is the whole audit trail. Someone will read it in three weeks when
126
+ they are asking why this card took a week, and the card id will not tell them.
127
+ The tool refuses placeholder reasons — "moved", "update", "Moved to another
128
+ column" — on purpose: a history full of those looks like an audit trail, so
129
+ nobody goes looking for the real answer, which is worse than no history at all.
130
+
131
+ **Do not move a card into the terminal column** — `Production` on a default
132
+ board, or whatever the last column is called on this one. That is a human's call:
133
+ the person who reported it, or the reviewer. An agent marking its own work
134
+ complete is the one move on this board that nobody can trust. Stop at the review
135
+ or QA column and say it is ready.
136
+
137
+ ## Writes
138
+
139
+ Comments and flags are governed writes too, on the same contract as a move, and
140
+ the idempotency key matters there for a quieter reason: a replayed comment posts
141
+ the same paragraph twice, which reads as you being emphatic rather than as a
142
+ retry.
143
+
144
+ Every move is governed: preview first, then `dryRun: false`, `approved: true`, a
145
+ `reason`, and an `idempotencyKey`. Reuse the same key on retry. A duplicate
146
+ transition makes the card read as having bounced, and the stage timer is derived
147
+ from exactly those rows — so a retry without a key does not just add noise, it
148
+ rewrites how long the work appears to have taken.
149
+
150
+ ## What to report
151
+
152
+ - the card, where it is now, and whether you left it flagged;
153
+ - what changed, and how it was verified;
154
+ - anything you found that should be its own card, stated as a title someone
155
+ could file as-is.