ticketwright 2.0.0__py3-none-any.whl
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.
- ticketwright/__init__.py +9 -0
- ticketwright/_kit/.claude/agents/qc-reviewer.md +50 -0
- ticketwright/_kit/.claude/commands/build-context-pack.md +8 -0
- ticketwright/_kit/.claude/commands/build-ticket-index.md +8 -0
- ticketwright/_kit/.claude/commands/configure-workspace.md +8 -0
- ticketwright/_kit/.claude/commands/deliver-ticket.md +8 -0
- ticketwright/_kit/.claude/commands/onboard-teammate.md +8 -0
- ticketwright/_kit/.claude/commands/prime-domain.md +8 -0
- ticketwright/_kit/.claude/commands/prime-ticket.md +8 -0
- ticketwright/_kit/.claude/commands/prime-warehouse.md +8 -0
- ticketwright/_kit/.claude/commands/productize-workflow.md +8 -0
- ticketwright/_kit/.claude/commands/qc-review.md +8 -0
- ticketwright/_kit/.claude/commands/recall.md +8 -0
- ticketwright/_kit/.claude/commands/start-ticket.md +8 -0
- ticketwright/_kit/.claude/config/stack.example.asana-bq.yaml +67 -0
- ticketwright/_kit/.claude/config/stack.example.azure.yaml +73 -0
- ticketwright/_kit/.claude/config/stack.schema.md +76 -0
- ticketwright/_kit/.claude/config/stack.yaml +76 -0
- ticketwright/_kit/.claude/hooks/db_write_guard.py +145 -0
- ticketwright/_kit/.claude/hooks/regenerate_ticket_index.py +74 -0
- ticketwright/_kit/.claude/hooks/session_context.py +78 -0
- ticketwright/_kit/.claude/hooks/ticket_index_context.py +99 -0
- ticketwright/_kit/.claude/settings.json.tmpl +59 -0
- ticketwright/_kit/.claude/skills/productize/SKILL.md +58 -0
- ticketwright/_kit/.claude/skills/productize/authoring.md +36 -0
- ticketwright/_kit/.claude/skills/refresh/SKILL.md +40 -0
- ticketwright/_kit/.claude/skills/refresh/context-pack.md +34 -0
- ticketwright/_kit/.claude/skills/refresh/index.md +45 -0
- ticketwright/_kit/.claude/skills/review/SKILL.md +76 -0
- ticketwright/_kit/.claude/skills/setup/SKILL.md +59 -0
- ticketwright/_kit/.claude/skills/setup/adopt.md +43 -0
- ticketwright/_kit/.claude/skills/setup/scaffold.md +38 -0
- ticketwright/_kit/.claude/skills/setup/teammate.md +33 -0
- ticketwright/_kit/.claude/skills/ship/SKILL.md +53 -0
- ticketwright/_kit/.claude/skills/spec-and-build/SKILL.md +54 -0
- ticketwright/_kit/.claude/skills/ticket/SKILL.md +59 -0
- ticketwright/_kit/.claude/skills/ticket/priming.md +47 -0
- ticketwright/_kit/.claude/statusline.sh +22 -0
- ticketwright/_kit/adapters/README.md +103 -0
- ticketwright/_kit/adapters/chat/slack.md +46 -0
- ticketwright/_kit/adapters/chat/teams.md +38 -0
- ticketwright/_kit/adapters/docstore/gdrive.md +39 -0
- ticketwright/_kit/adapters/docstore/sharepoint.md +41 -0
- ticketwright/_kit/adapters/tracker/asana.md +55 -0
- ticketwright/_kit/adapters/tracker/azure-devops.md +68 -0
- ticketwright/_kit/adapters/tracker/github-issues.md +59 -0
- ticketwright/_kit/adapters/tracker/jira.md +71 -0
- ticketwright/_kit/adapters/tracker/linear.md +56 -0
- ticketwright/_kit/adapters/tracker/monday.md +62 -0
- ticketwright/_kit/adapters/vcs/azure-repos.md +58 -0
- ticketwright/_kit/adapters/vcs/github.md +55 -0
- ticketwright/_kit/adapters/vcs/gitlab.md +52 -0
- ticketwright/_kit/adapters/warehouse/bigquery.md +44 -0
- ticketwright/_kit/adapters/warehouse/databricks.md +58 -0
- ticketwright/_kit/adapters/warehouse/postgres.md +44 -0
- ticketwright/_kit/adapters/warehouse/redshift.md +49 -0
- ticketwright/_kit/adapters/warehouse/snowflake.md +54 -0
- ticketwright/_kit/adapters/warehouse/synapse.md +52 -0
- ticketwright/_kit/bin/build_ticket_index.py +498 -0
- ticketwright/_kit/bin/enrich_ticket.py +138 -0
- ticketwright/_kit/bin/ingest_index_records.py +149 -0
- ticketwright/_kit/bin/recall.py +268 -0
- ticketwright/_kit/bin/render.sh +54 -0
- ticketwright/_kit/bin/render_and_validate.sh +139 -0
- ticketwright/_kit/bin/selftest.sh +408 -0
- ticketwright/_kit/bin/split_and_export.sh +138 -0
- ticketwright/_kit/bin/verify_stack.sh +74 -0
- ticketwright/_kit/templates/AGENTS.md.tmpl +74 -0
- ticketwright/_kit/templates/gitignore.tmpl +35 -0
- ticketwright/_kit/templates/plan.md.tmpl +22 -0
- ticketwright/_kit/templates/productized-skill/SKILL.md.tmpl +67 -0
- ticketwright/_kit/templates/productized-skill/bin/drift_check.sh +30 -0
- ticketwright/_kit/templates/productized-skill/golden/example.json +13 -0
- ticketwright/_kit/templates/productized-skill/sql/qc.sql.tmpl +21 -0
- ticketwright/_kit/templates/productized-skill/sql/step.sql.tmpl +20 -0
- ticketwright/_kit/templates/productized-skill/templates/README.md.tmpl +20 -0
- ticketwright/_kit/templates/productized-skill/templates/tracker_comment.txt.tmpl +14 -0
- ticketwright/_kit/templates/roles/analyst.md +6 -0
- ticketwright/_kit/templates/roles/engineer.md +6 -0
- ticketwright/_kit/templates/roles/generalist.md +3 -0
- ticketwright/_kit/templates/roles/scientist.md +5 -0
- ticketwright/_kit/templates/spec.md.tmpl +34 -0
- ticketwright/_kit/templates/ticket-README.md.tmpl +29 -0
- ticketwright/cli.py +115 -0
- ticketwright-2.0.0.dist-info/METADATA +139 -0
- ticketwright-2.0.0.dist-info/RECORD +89 -0
- ticketwright-2.0.0.dist-info/WHEEL +4 -0
- ticketwright-2.0.0.dist-info/entry_points.txt +2 -0
- ticketwright-2.0.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
seam: docstore
|
|
3
|
+
tool: sharepoint
|
|
4
|
+
transport: cli # OneDrive/SharePoint sync folder (filesystem), or MS Graph API
|
|
5
|
+
requires: [base_path] # stack.yaml seams.docstore.{base_path, drive_id?}
|
|
6
|
+
auth: |
|
|
7
|
+
OneDrive/SharePoint sync mounted at base_path, OR a Graph API token (Files.ReadWrite.All).
|
|
8
|
+
Verify (synced): `test -d "{base_path}"`.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# SharePoint / OneDrive adapter
|
|
12
|
+
|
|
13
|
+
Maps the `docstore` verb contract to SharePoint/OneDrive. Two transports: the **synced folder**
|
|
14
|
+
(simplest — treat like a local path) or the **Graph API** (when nothing is mounted).
|
|
15
|
+
|
|
16
|
+
## verb: backup
|
|
17
|
+
**In:** local ticket dir, dest name (**always full title, not just the ID**).
|
|
18
|
+
```bash
|
|
19
|
+
# Synced transport:
|
|
20
|
+
dest="{base_path}/<TICKET-ID> <Full Ticket Title>"
|
|
21
|
+
rm -rf "$dest" # remove ONLY this exact destination (never a wildcard like <ID>*)
|
|
22
|
+
cp -r "<local ticket dir>" "$dest"
|
|
23
|
+
ls -la "$dest" # verify
|
|
24
|
+
|
|
25
|
+
# Graph transport (per file):
|
|
26
|
+
# PUT https://graph.microsoft.com/v1.0/drives/{drive_id}/root:/<path>/<file>:/content
|
|
27
|
+
```
|
|
28
|
+
External side effect ⇒ policy `hard_halt_before_external_posts` (approval first).
|
|
29
|
+
|
|
30
|
+
## verb: link_for
|
|
31
|
+
**In:** a backed-up file. **Out:** a shareable URL for tracker/chat smart links.
|
|
32
|
+
```
|
|
33
|
+
# Synced: derive the web URL from the SharePoint library's sync-path → URL mapping.
|
|
34
|
+
# Graph: POST /drives/{drive_id}/items/{item-id}/createLink { "type": "view", "scope": "organization" }
|
|
35
|
+
# → response.link.webUrl
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## gotchas
|
|
39
|
+
- Sync can lag — confirm the file appears in the library before generating a link.
|
|
40
|
+
- Org sharing policy may force "people in your org only"; pick the `scope` your stakeholders can open.
|
|
41
|
+
- Large *exports* live here and are linked; committed git holds only inputs/provenance.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
seam: tracker
|
|
3
|
+
tool: asana
|
|
4
|
+
transport: mcp # mcp__plugin_productivity_asana__*
|
|
5
|
+
requires: [workspace_gid] # stack.yaml seams.tracker.{workspace_gid, default_project_gid}
|
|
6
|
+
auth: |
|
|
7
|
+
The `asana` MCP server (plugin_productivity_asana) must be connected (OAuth).
|
|
8
|
+
Verify: an Asana MCP "list workspaces" / "typeahead search" call returns without error.
|
|
9
|
+
note: |
|
|
10
|
+
Asana has no "Epic" concept — `default_epic` maps to a parent task or a project section.
|
|
11
|
+
Asana task GIDs are the ticket "id"; there is no DI-style prefix, so set project.key_prefix to a
|
|
12
|
+
short tag you add to task names (e.g. "DI") if you want branch parity.
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Asana adapter (reference for the abstraction proof)
|
|
16
|
+
|
|
17
|
+
Maps the `tracker` verb contract to Asana via its MCP. Demonstrates that swapping Jira→Asana is a
|
|
18
|
+
**config + adapter** change with **zero skill edits** — the skills still call `tracker.fetch_ticket`.
|
|
19
|
+
|
|
20
|
+
## verb: fetch_ticket
|
|
21
|
+
**In:** task GID. **Out:** name, notes, status (section/custom field), assignee, links, attachments.
|
|
22
|
+
```
|
|
23
|
+
mcp__plugin_productivity_asana__* get-task(task_gid=<id>)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## verb: create_ticket
|
|
27
|
+
```
|
|
28
|
+
create-task(workspace={workspace_gid}, projects=[{default_project_gid}],
|
|
29
|
+
name=<summary>, notes=<desc>, assignee=<email/gid>)
|
|
30
|
+
```
|
|
31
|
+
Parent/epic → set `parent` task GID or add to a project section instead of `--parent`.
|
|
32
|
+
|
|
33
|
+
## verb: transition
|
|
34
|
+
Asana "status" = moving a task between **sections** or setting a custom field.
|
|
35
|
+
```
|
|
36
|
+
update-task(task_gid=<id>, ...) / add-task-to-section(section_gid=<terminal_status section>)
|
|
37
|
+
```
|
|
38
|
+
`terminal_status` in stack.yaml names the "done" section.
|
|
39
|
+
|
|
40
|
+
## verb: comment
|
|
41
|
+
```
|
|
42
|
+
create-task-comment(task_gid=<id>, text=<body with URLs>)
|
|
43
|
+
```
|
|
44
|
+
Asana stories render URLs inline. Honor `word_limits.tracker_comment`; never post pre-review.
|
|
45
|
+
|
|
46
|
+
## verb: search
|
|
47
|
+
```
|
|
48
|
+
search-tasks(workspace={workspace_gid}, text=<topic>) # or typeahead-search
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## verb: download_attachments
|
|
52
|
+
```
|
|
53
|
+
get-attachments-for-task(task_gid=<id>) → download each attachment's `download_url` with curl
|
|
54
|
+
```
|
|
55
|
+
(No prebuilt script like Jira's — fall back to curl per attachment.)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
seam: tracker
|
|
3
|
+
tool: azure-devops
|
|
4
|
+
transport: cli # `az boards` (Azure CLI + azure-devops extension); REST API as fallback
|
|
5
|
+
requires: [org, project] # stack.yaml seams.tracker.{org, project, done_state}
|
|
6
|
+
auth: |
|
|
7
|
+
`az login` + the devops extension: `az extension add --name azure-devops`.
|
|
8
|
+
Set defaults: `az devops configure --defaults organization=https://dev.azure.com/{org} project={project}`.
|
|
9
|
+
A PAT (env `AZURE_DEVOPS_EXT_PAT`) works for non-interactive/CI.
|
|
10
|
+
Verify: `az boards work-item show --id {default_epic}` (read-only) or `az devops project show`.
|
|
11
|
+
note: |
|
|
12
|
+
Azure Boards "work items" are the tickets; ids are plain integers (e.g. 1234), so `key_prefix` is a
|
|
13
|
+
display convention, not part of the id. "Epic" is a work-item type (Epic→Feature→User Story→Task)
|
|
14
|
+
linked via parent/child relations; "status" = the work item's **State** (New / Active / Resolved /
|
|
15
|
+
Closed, or your process's states). Convention: name ticket folders/branches `{key_prefix}-<number>`
|
|
16
|
+
so the index discovers them, but set `ticket_url_template` to use the `{number}` token (not `{id}`)
|
|
17
|
+
and pass the bare integer to `az boards` — the work-item URL and CLI need the number, not the prefix.
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
# Azure DevOps (Boards) adapter
|
|
21
|
+
|
|
22
|
+
Maps the `tracker` verb contract to Azure Boards via the `az boards` CLI.
|
|
23
|
+
|
|
24
|
+
## verb: fetch_ticket
|
|
25
|
+
**In:** work-item id (integer). **Out:** title, description, state, type, assignee, relations, attachments.
|
|
26
|
+
```bash
|
|
27
|
+
az boards work-item show --id <id> --output json
|
|
28
|
+
```
|
|
29
|
+
Description is `fields."System.Description"` (HTML). Relations (parents, attachments) are in `relations`.
|
|
30
|
+
|
|
31
|
+
## verb: create_ticket
|
|
32
|
+
```bash
|
|
33
|
+
az boards work-item create --title "<summary>" --type "User Story" \
|
|
34
|
+
--assigned-to "<email>" --fields "System.Description=<html/desc>" --output json
|
|
35
|
+
# link to an epic/feature parent:
|
|
36
|
+
az boards work-item relation add --id <new-id> --relation-type parent --target-id {default_epic}
|
|
37
|
+
```
|
|
38
|
+
Returns the new integer id + `_links.html.href` (the URL).
|
|
39
|
+
|
|
40
|
+
## verb: transition
|
|
41
|
+
```bash
|
|
42
|
+
az boards work-item update --id <id> --state "<State>" # e.g. {done_state} for terminal_status
|
|
43
|
+
```
|
|
44
|
+
States are process-specific (Agile: New/Active/Resolved/Closed; Basic: To Do/Doing/Done) — map
|
|
45
|
+
`project.terminal_status` → `{done_state}`.
|
|
46
|
+
|
|
47
|
+
## verb: comment
|
|
48
|
+
```bash
|
|
49
|
+
az boards work-item update --id <id> --discussion "<body>" # adds a comment to the work item
|
|
50
|
+
```
|
|
51
|
+
Discussion accepts HTML (links render). Honor `word_limits.tracker_comment`; never post before review.
|
|
52
|
+
|
|
53
|
+
## verb: search
|
|
54
|
+
```bash
|
|
55
|
+
az boards query --wiql "SELECT [System.Id],[System.Title],[System.State] FROM workitems \
|
|
56
|
+
WHERE [System.TeamProject]='{project}' AND [System.Title] CONTAINS '<text>' \
|
|
57
|
+
ORDER BY [System.ChangedDate] DESC" --output json
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## verb: download_attachments
|
|
61
|
+
`az boards work-item show --id <id>` → `relations[?rel=='AttachedFile']`. Each has a `url`;
|
|
62
|
+
`curl -L -u :$AZURE_DEVOPS_EXT_PAT "<url>" -o <dest>/<name>` (silent if none).
|
|
63
|
+
|
|
64
|
+
## gotchas
|
|
65
|
+
- Ids are integers, not prefixed — keep `key_prefix` for branches/index display, but `fetch_ticket`
|
|
66
|
+
takes the bare number.
|
|
67
|
+
- State names differ per process template — resolve `{done_state}` from the project, don't assume "Done".
|
|
68
|
+
- HTML (not markdown) in description/discussion fields.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
seam: tracker
|
|
3
|
+
tool: github-issues
|
|
4
|
+
transport: cli # `gh issue` (GitHub CLI); REST/GraphQL as fallback
|
|
5
|
+
requires: [repo] # stack.yaml seams.tracker.{repo, done_label?} (repo = "owner/name")
|
|
6
|
+
auth: |
|
|
7
|
+
`gh auth login` (or `GH_TOKEN`). Verify: `gh auth status`.
|
|
8
|
+
note: |
|
|
9
|
+
GitHub Issues ids are per-repo integers (#123), so `key_prefix` is a branch/index display
|
|
10
|
+
convention, not part of the id — set `ticket_url_template` to use the `{number}` token and pass the
|
|
11
|
+
bare number to `gh issue`. "Epic" ≈ a tracking issue, a **milestone**, or a Project; "status"
|
|
12
|
+
≈ open/closed (+ optionally a Projects "Status" field or a label). If the same repo hosts code,
|
|
13
|
+
this pairs naturally with the `vcs: github` adapter.
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# GitHub Issues adapter
|
|
17
|
+
|
|
18
|
+
Maps the `tracker` verb contract to GitHub Issues via `gh`.
|
|
19
|
+
|
|
20
|
+
## verb: fetch_ticket
|
|
21
|
+
**In:** issue number. **Out:** title, body (markdown), state, assignees, labels, milestone.
|
|
22
|
+
```bash
|
|
23
|
+
gh issue view <number> --repo {repo} --json number,title,body,state,assignees,labels,milestone,url
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## verb: create_ticket
|
|
27
|
+
```bash
|
|
28
|
+
gh issue create --repo {repo} --title "<summary>" --body "<markdown>" \
|
|
29
|
+
--assignee "<login>" --label "<type>" --milestone "<epic>"
|
|
30
|
+
```
|
|
31
|
+
Returns the new issue URL (number is the id). Epic → `--milestone` or a parent tracking issue.
|
|
32
|
+
|
|
33
|
+
## verb: transition
|
|
34
|
+
```bash
|
|
35
|
+
gh issue close <number> --repo {repo} # map terminal_status → closed
|
|
36
|
+
gh issue edit <number> --repo {repo} --add-label "{done_label}" # if you track status via labels/Projects
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## verb: comment
|
|
40
|
+
```bash
|
|
41
|
+
gh issue comment <number> --repo {repo} --body "<markdown>"
|
|
42
|
+
```
|
|
43
|
+
Full markdown links render. Honor `word_limits.tracker_comment`; never post before human review.
|
|
44
|
+
|
|
45
|
+
## verb: search
|
|
46
|
+
```bash
|
|
47
|
+
gh issue list --repo {repo} --search "<query>" --state all --limit <n> \
|
|
48
|
+
--json number,title,state
|
|
49
|
+
```
|
|
50
|
+
`--search` takes GitHub's issue search syntax (`is:open label:bug ...`).
|
|
51
|
+
|
|
52
|
+
## verb: download_attachments
|
|
53
|
+
GitHub stores issue attachments as URLs embedded in the body/comments. Parse them
|
|
54
|
+
(`gh issue view --json body,comments`), then `curl -L "<url>" -o <dest>/<name>` (silent if none).
|
|
55
|
+
|
|
56
|
+
## gotchas
|
|
57
|
+
- Ids are bare numbers — `fetch_ticket` takes `123`, not `PROJ-123`.
|
|
58
|
+
- "Status" is open/closed unless you adopt a Projects Status field or label convention — set
|
|
59
|
+
`done_label` (or map terminal_status → closed) so `transition` is unambiguous.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
seam: tracker
|
|
3
|
+
tool: jira
|
|
4
|
+
transport: both # acli (CLI) for reads/creates/transitions; Atlassian MCP for rich comments
|
|
5
|
+
requires: [site, cli] # stack.yaml seams.tracker.{site, cli, mcp, default_epic, terminal_status}
|
|
6
|
+
auth: |
|
|
7
|
+
CLI: acli jira auth (token in ~/.config/acli/token.txt; site/email in jira_config.yaml)
|
|
8
|
+
MCP: the `atlassian` MCP server must be connected (OAuth). Used for comment rendering.
|
|
9
|
+
Verify: `acli jira workitem view {default_epic}` (read-only).
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Jira adapter
|
|
13
|
+
|
|
14
|
+
Maps the `tracker` verb contract to Atlassian Jira via the `acli` CLI and the Atlassian MCP server.
|
|
15
|
+
Reads/creates/transitions go through `acli`; **comments go through the MCP** because ADF renders
|
|
16
|
+
clickable smart links and @mentions (acli posts plain text — links don't render).
|
|
17
|
+
|
|
18
|
+
## verb: fetch_ticket
|
|
19
|
+
**In:** `id` (e.g. `ENG-1234`). **Out:** title, description, status, type, assignee, links.
|
|
20
|
+
```bash
|
|
21
|
+
acli jira workitem view <id>
|
|
22
|
+
```
|
|
23
|
+
For structured fields: `acli jira workitem view <id> --json`.
|
|
24
|
+
|
|
25
|
+
## verb: create_ticket
|
|
26
|
+
**In:** type, summary, description, assignee (email), parent/epic.
|
|
27
|
+
```bash
|
|
28
|
+
acli jira workitem create \
|
|
29
|
+
--project "{key_prefix}" --type "<TYPE>" \
|
|
30
|
+
--summary "<SUMMARY>" --description "<DESC>" \
|
|
31
|
+
--assignee "<email>" --parent "<epic or {default_epic}>"
|
|
32
|
+
```
|
|
33
|
+
Notes: **every DI type needs `--parent` (an Epic)** or create fails. Assignee is the **email**, not
|
|
34
|
+
username. Valid types: Reporting, Data Pull, Automation, Dashboard, Research, Data Engineering Task,
|
|
35
|
+
Data Engineering Bug, Epic.
|
|
36
|
+
|
|
37
|
+
## verb: transition
|
|
38
|
+
```bash
|
|
39
|
+
acli jira workitem transition --key "<id>" --status "<status>"
|
|
40
|
+
```
|
|
41
|
+
The done state is `{terminal_status}` (here `Deployed`, not "Done"). Common: Backlog, In Spec,
|
|
42
|
+
In-Progress, Blocked, Deployed.
|
|
43
|
+
|
|
44
|
+
## verb: comment
|
|
45
|
+
Use the **Atlassian MCP**, not acli — ADF format renders links/mentions.
|
|
46
|
+
```
|
|
47
|
+
mcp__atlassian__addCommentToJiraIssue(cloudId, issueIdOrKey=<id>, commentBody=<ADF>)
|
|
48
|
+
```
|
|
49
|
+
For a clickable Google-Drive Smart Link, embed an `inlineCard` ADF node with the file URL (see
|
|
50
|
+
docstore/gdrive.md `link_for`). Plain text only otherwise — Jira has its own formatter (no markdown).
|
|
51
|
+
Honor `word_limits.tracker_comment`. **Never post until the human has reviewed** (policy
|
|
52
|
+
`hard_halt_before_external_posts`).
|
|
53
|
+
|
|
54
|
+
## verb: search
|
|
55
|
+
```bash
|
|
56
|
+
acli jira workitem search --jql "<JQL>" --limit <N> --json # --csv / --fields also supported
|
|
57
|
+
# MCP alt: mcp__atlassian__searchJiraIssuesUsingJql
|
|
58
|
+
```
|
|
59
|
+
Example (related prior tickets): `project = {key_prefix} AND text ~ "<topic>" ORDER BY created DESC`.
|
|
60
|
+
|
|
61
|
+
## verb: download_attachments
|
|
62
|
+
Pull a ticket's attachments into its `source_materials/` (skip silently when there are none).
|
|
63
|
+
`acli jira workitem attachment list <id>` only LISTS attachments — to DOWNLOAD, use a small `curl`
|
|
64
|
+
script against the REST API that follows the 303 redirect to the download URL:
|
|
65
|
+
```bash
|
|
66
|
+
# e.g. a helper you keep in bin/: download_jira_attachments.sh <id> <dest_dir>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## gotchas
|
|
70
|
+
- `acli` Duo/MFA: an instant `250001/370001` = lockout (wait 15 min, don't retry); a hang = push pending.
|
|
71
|
+
- Epic link errors ⇒ you forgot `--parent`. "User not found" ⇒ use the exact email.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
seam: tracker
|
|
3
|
+
tool: linear
|
|
4
|
+
transport: mcp # mcp__plugin_productivity_linear__*
|
|
5
|
+
requires: [team_id] # stack.yaml seams.tracker.{team_id, done_state_id}
|
|
6
|
+
auth: |
|
|
7
|
+
The `linear` MCP server (plugin_productivity_linear) must be connected (OAuth).
|
|
8
|
+
Verify: a read-only issue/team query returns without error.
|
|
9
|
+
note: |
|
|
10
|
+
Linear has first-class issue identifiers (e.g. ENG-123) — a natural fit for project.key_prefix and
|
|
11
|
+
branch names (Linear even suggests `username/eng-123-slug`). "Epic" ≈ a **Project** or a parent
|
|
12
|
+
issue; "status" = workflow **state** (Backlog / Todo / In Progress / Done / Canceled).
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Linear adapter
|
|
16
|
+
|
|
17
|
+
Maps the `tracker` verb contract to Linear via its MCP.
|
|
18
|
+
|
|
19
|
+
## verb: fetch_ticket
|
|
20
|
+
**In:** issue id (e.g. `ENG-123`). **Out:** title, description (markdown), state, assignee, labels,
|
|
21
|
+
attachments, parent/project.
|
|
22
|
+
```
|
|
23
|
+
mcp__plugin_productivity_linear__* get-issue(id=<id>)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## verb: create_ticket
|
|
27
|
+
```
|
|
28
|
+
create-issue(team={team_id}, title=<summary>, description=<markdown>,
|
|
29
|
+
assignee=<email/userId>, project=<epic project id>, parentId=<optional>)
|
|
30
|
+
```
|
|
31
|
+
Linear auto-mints the identifier from `{team_id}` (your `key_prefix`). Epic → set `project` or `parentId`.
|
|
32
|
+
|
|
33
|
+
## verb: transition
|
|
34
|
+
```
|
|
35
|
+
update-issue(id=<id>, stateId={done_state_id}) # move to the workflow state for terminal_status
|
|
36
|
+
```
|
|
37
|
+
Fetch the team's states once to map `project.terminal_status` → `{done_state_id}`.
|
|
38
|
+
|
|
39
|
+
## verb: comment
|
|
40
|
+
```
|
|
41
|
+
create-comment(issueId=<id>, body=<markdown>)
|
|
42
|
+
```
|
|
43
|
+
Linear comments support full markdown links — `[DI-123](url)`, file links, PR links. Honor
|
|
44
|
+
`word_limits.tracker_comment`; never post before human review.
|
|
45
|
+
|
|
46
|
+
## verb: search
|
|
47
|
+
```
|
|
48
|
+
list-issues(team={team_id}, query=<text>, filter={state, label, ...})
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## verb: download_attachments
|
|
52
|
+
Read the issue's `attachments{ url }`, `curl -L` each to the dest dir. (Linear attachments are URLs.)
|
|
53
|
+
|
|
54
|
+
## gotchas
|
|
55
|
+
- State ids are team-specific — don't hardcode; resolve from the team's workflow states.
|
|
56
|
+
- Linear's native git-branch naming convention pairs well with the `vcs.branch` verb.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
seam: tracker
|
|
3
|
+
tool: monday
|
|
4
|
+
transport: mcp # mcp__plugin_productivity_monday__* (GraphQL under the hood)
|
|
5
|
+
requires: [board_id] # stack.yaml seams.tracker.{board_id, status_column_id, done_label}
|
|
6
|
+
auth: |
|
|
7
|
+
The `monday` MCP server (plugin_productivity_monday) must be connected (OAuth).
|
|
8
|
+
Verify: a read-only board/items query returns without error.
|
|
9
|
+
note: |
|
|
10
|
+
monday models work as **items** on **boards**. "Status" is a status **column** (set by label),
|
|
11
|
+
not a workflow transition; "epic" maps to a parent item or a board **group**. There is no DI-style
|
|
12
|
+
id prefix — item ids are numeric, so set project.key_prefix to a short tag you put in item names if
|
|
13
|
+
you want branch parity (e.g. branch "OPS-<itemId>").
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# monday.com adapter
|
|
17
|
+
|
|
18
|
+
Maps the `tracker` verb contract to monday.com via its MCP (GraphQL items API).
|
|
19
|
+
|
|
20
|
+
## verb: fetch_ticket
|
|
21
|
+
**In:** item id. **Out:** name, column values (incl. status), updates, assignee, file-column assets.
|
|
22
|
+
```
|
|
23
|
+
mcp__plugin_productivity_monday__* get-item(item_id=<id>)
|
|
24
|
+
# or GraphQL: items(ids:[<id>]){ name column_values{ id text value } updates{ body } assets{ url } }
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## verb: create_ticket
|
|
28
|
+
```
|
|
29
|
+
create-item(board_id={board_id}, item_name=<summary>,
|
|
30
|
+
column_values={ "status": {"label":"<initial>"}, "person": {"personsAndTeams":[…]} })
|
|
31
|
+
```
|
|
32
|
+
Parent/epic → create as a **subitem** of the parent item, or place in the epic **group** (`group_id`).
|
|
33
|
+
monday has no `--parent` flag; the group/subitem is the equivalent.
|
|
34
|
+
|
|
35
|
+
## verb: transition
|
|
36
|
+
"Status" = set the status column's label to `{done_label}` (or any workflow label).
|
|
37
|
+
```
|
|
38
|
+
change-column-value(item_id=<id>, board_id={board_id}, column_id={status_column_id},
|
|
39
|
+
value="{\"label\":\"<status>\"}")
|
|
40
|
+
```
|
|
41
|
+
`project.terminal_status` maps to `{done_label}`.
|
|
42
|
+
|
|
43
|
+
## verb: comment
|
|
44
|
+
```
|
|
45
|
+
create-update(item_id=<id>, body=<text with URLs>)
|
|
46
|
+
```
|
|
47
|
+
Updates render links inline. Honor `word_limits.tracker_comment`. Never post before human review
|
|
48
|
+
(policy `hard_halt_before_external_posts`).
|
|
49
|
+
|
|
50
|
+
## verb: search
|
|
51
|
+
```
|
|
52
|
+
items-page-by-column-values(board_id={board_id}, columns=[…]) # filter by column
|
|
53
|
+
# or a text query across the board's items
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## verb: download_attachments
|
|
57
|
+
Read the item's **file column** `assets{ url }`, then `curl -L <asset url> -o <dest>` per file.
|
|
58
|
+
(No prebuilt script like Jira's.)
|
|
59
|
+
|
|
60
|
+
## gotchas
|
|
61
|
+
- Status changes require the exact **label text** the board defines — fetch the column's labels first.
|
|
62
|
+
- monday rate-limits GraphQL by complexity; batch item reads rather than looping single-item calls.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
seam: vcs
|
|
3
|
+
tool: azure-repos
|
|
4
|
+
transport: cli # git + `az repos` (Azure CLI + azure-devops extension)
|
|
5
|
+
requires: [default_branch] # stack.yaml seams.vcs.{default_branch, semantic_pr, worktree_root, org, project, repo}
|
|
6
|
+
auth: |
|
|
7
|
+
`az login` + `az extension add --name azure-devops`; git creds via Git Credential Manager or a PAT.
|
|
8
|
+
Set defaults: `az devops configure --defaults organization=https://dev.azure.com/{org} project={project}`.
|
|
9
|
+
Verify: `az repos list --query "[].name"` (or `az devops project show`).
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Azure Repos adapter
|
|
13
|
+
|
|
14
|
+
Maps the `vcs` verb contract to git + the `az repos` CLI (Azure DevOps Pull Requests). Mirrors the
|
|
15
|
+
GitHub/GitLab flow; "PR" = Azure DevOps Pull Request. Pairs with the `azure-devops` tracker when the
|
|
16
|
+
whole stack is Microsoft.
|
|
17
|
+
|
|
18
|
+
## verb: branch
|
|
19
|
+
```bash
|
|
20
|
+
git checkout {default_branch} && git pull origin {default_branch}
|
|
21
|
+
git checkout -b <TICKET-ID>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## verb: worktree (the Plan→Implement context reset)
|
|
25
|
+
```bash
|
|
26
|
+
git worktree add "{worktree_root}/<name>" -b <TICKET-ID>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## verb: commit
|
|
30
|
+
Stage only files you changed (never `git add .`); semantic message + trailer.
|
|
31
|
+
```bash
|
|
32
|
+
git add <paths>
|
|
33
|
+
git commit -m "$(cat <<'EOF'
|
|
34
|
+
<type>: <TICKET-ID> <description>
|
|
35
|
+
|
|
36
|
+
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
37
|
+
EOF
|
|
38
|
+
)"
|
|
39
|
+
```
|
|
40
|
+
Types: feat, fix, docs, refactor, chore, test, ci. Small atomic commits per build step; commit the
|
|
41
|
+
plan/spec artifact before implementing (policy `commit_plan_before_implement`).
|
|
42
|
+
|
|
43
|
+
## verb: open_pr
|
|
44
|
+
```bash
|
|
45
|
+
git push -u origin <TICKET-ID>
|
|
46
|
+
az repos pr create --repository {repo} --source-branch <TICKET-ID> --target-branch {default_branch} \
|
|
47
|
+
--title "<type>: <TICKET-ID> <description>" \
|
|
48
|
+
--description "Business Impact / Deliverables / Technical Notes / QC Results" \
|
|
49
|
+
--work-items <ticket-number> # links the PR to the Boards work item
|
|
50
|
+
```
|
|
51
|
+
`semantic_pr: true` ⇒ keep the title semantic if branch policies lint it. Honor `word_limits.pr`.
|
|
52
|
+
External action ⇒ requires approval (policy `hard_halt_before_external_posts`).
|
|
53
|
+
|
|
54
|
+
## gotchas
|
|
55
|
+
- `--work-items` ties the PR to the Azure Boards item (the tracker side) — use the bare integer id.
|
|
56
|
+
- Branch policies (required reviewers, build validation) may gate completion — surface required
|
|
57
|
+
approvals rather than force-completing the PR.
|
|
58
|
+
- Self-hosted Azure DevOps Server uses `--organization https://<server>/<collection>`.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
seam: vcs
|
|
3
|
+
tool: github
|
|
4
|
+
transport: cli # git + gh
|
|
5
|
+
requires: [default_branch] # stack.yaml seams.vcs.{default_branch, semantic_pr, worktree_root}
|
|
6
|
+
auth: |
|
|
7
|
+
git credentials in keychain; `gh auth login` for PRs.
|
|
8
|
+
Verify: `gh auth status`.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# GitHub adapter
|
|
12
|
+
|
|
13
|
+
Maps the `vcs` verb contract to git + the GitHub CLI. Branch = ticket ID; PR titles are semantic.
|
|
14
|
+
|
|
15
|
+
## verb: branch
|
|
16
|
+
```bash
|
|
17
|
+
git checkout {default_branch} && git pull origin {default_branch}
|
|
18
|
+
git checkout -b <TICKET-ID> # branch name IS the ticket id
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## verb: worktree (the Plan→Implement context reset)
|
|
22
|
+
```bash
|
|
23
|
+
git worktree add "{worktree_root}/<name>" -b <TICKET-ID>
|
|
24
|
+
```
|
|
25
|
+
A fresh worktree gives implementation its own clean context, separate from planning. (This repo's
|
|
26
|
+
worktree-manager scripts under `~/.claude/skills/worktree-manager/` can also be used.)
|
|
27
|
+
|
|
28
|
+
## verb: commit
|
|
29
|
+
Stage only files you changed (never `git add .`); semantic message.
|
|
30
|
+
```bash
|
|
31
|
+
git add <paths>
|
|
32
|
+
git commit -m "$(cat <<'EOF'
|
|
33
|
+
<type>: <TICKET-ID> <description>
|
|
34
|
+
|
|
35
|
+
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
36
|
+
EOF
|
|
37
|
+
)"
|
|
38
|
+
```
|
|
39
|
+
Types: feat, fix, docs, refactor, chore, test, ci. Small atomic commits per build step (git-log-is-memory).
|
|
40
|
+
Commit the **plan/spec artifact before implementing** (policy `commit_plan_before_implement`).
|
|
41
|
+
|
|
42
|
+
## verb: open_pr
|
|
43
|
+
```bash
|
|
44
|
+
git push -u origin <TICKET-ID> # gh pr create is interactive if the branch isn't pushed yet
|
|
45
|
+
gh pr create --title "<type>: <TICKET-ID> <description>" \
|
|
46
|
+
--body "Business Impact / Deliverables / Technical Notes / QC Results"
|
|
47
|
+
```
|
|
48
|
+
`semantic_pr: true` ⇒ non-semantic titles fail the Semantic-PR check. Honor `word_limits.pr` (<200).
|
|
49
|
+
External action ⇒ requires approval (policy `hard_halt_before_external_posts`).
|
|
50
|
+
|
|
51
|
+
## gotchas
|
|
52
|
+
- `gh pr create` prompts interactively (which can hang an agent) unless the branch is already pushed
|
|
53
|
+
— push first, as above.
|
|
54
|
+
- Branch protection / required status checks may gate the merge — surface the required reviews/checks
|
|
55
|
+
rather than force-merging.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
seam: vcs
|
|
3
|
+
tool: gitlab
|
|
4
|
+
transport: cli # git + `glab` CLI
|
|
5
|
+
requires: [default_branch] # stack.yaml seams.vcs.{default_branch, semantic_pr, worktree_root}
|
|
6
|
+
auth: |
|
|
7
|
+
git credentials in keychain/credential-helper; `glab auth login` for merge requests.
|
|
8
|
+
Verify: `glab auth status`.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# GitLab adapter
|
|
12
|
+
|
|
13
|
+
Maps the `vcs` verb contract to git + the GitLab CLI. Merge Requests (MRs) replace PRs; otherwise the
|
|
14
|
+
flow mirrors GitHub. Branch = ticket id; MR titles are semantic.
|
|
15
|
+
|
|
16
|
+
## verb: branch
|
|
17
|
+
```bash
|
|
18
|
+
git checkout {default_branch} && git pull origin {default_branch}
|
|
19
|
+
git checkout -b <TICKET-ID>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## verb: worktree (the Plan→Implement context reset)
|
|
23
|
+
```bash
|
|
24
|
+
git worktree add "{worktree_root}/<name>" -b <TICKET-ID>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## verb: commit
|
|
28
|
+
Stage only files you changed (never `git add .`); semantic message + trailer.
|
|
29
|
+
```bash
|
|
30
|
+
git add <paths>
|
|
31
|
+
git commit -m "$(cat <<'EOF'
|
|
32
|
+
<type>: <TICKET-ID> <description>
|
|
33
|
+
|
|
34
|
+
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
35
|
+
EOF
|
|
36
|
+
)"
|
|
37
|
+
```
|
|
38
|
+
Types: feat, fix, docs, refactor, chore, test, ci. Small atomic commits per build step. Commit the
|
|
39
|
+
plan/spec artifact before implementing (policy `commit_plan_before_implement`).
|
|
40
|
+
|
|
41
|
+
## verb: open_pr
|
|
42
|
+
```bash
|
|
43
|
+
glab mr create --title "<type>: <TICKET-ID> <description>" \
|
|
44
|
+
--description "Business Impact / Deliverables / Technical Notes / QC Results" \
|
|
45
|
+
--target-branch {default_branch} --remove-source-branch
|
|
46
|
+
```
|
|
47
|
+
`semantic_pr: true` ⇒ keep the title semantic if a pipeline lint enforces it. Honor `word_limits.pr`.
|
|
48
|
+
External action ⇒ requires approval (policy `hard_halt_before_external_posts`).
|
|
49
|
+
|
|
50
|
+
## gotchas
|
|
51
|
+
- `glab` needs the host set for self-managed GitLab: `glab auth login --hostname <gitlab.company.com>`.
|
|
52
|
+
- MR approvals/merge-trains may gate the merge — surface required approvals rather than forcing.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
seam: warehouse
|
|
3
|
+
tool: bigquery
|
|
4
|
+
transport: cli # `bq` CLI (gcloud SDK)
|
|
5
|
+
requires: [project, dataset] # stack.yaml seams.warehouse.{project, dataset, dev_dataset}
|
|
6
|
+
auth: |
|
|
7
|
+
gcloud auth (ADC) + `bq` in PATH.
|
|
8
|
+
Verify: `bq query --use_legacy_sql=false --dry_run "SELECT 1"` (read-only, no cost).
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# BigQuery adapter (reference for the abstraction proof)
|
|
12
|
+
|
|
13
|
+
Maps the `warehouse` verb contract to Google BigQuery via `bq`. Same verbs as Snowflake — only the
|
|
14
|
+
commands and `dialect_notes` differ, so `review`/`spec-and-build`/`refresh context` run
|
|
15
|
+
unchanged.
|
|
16
|
+
|
|
17
|
+
## verb: query
|
|
18
|
+
```bash
|
|
19
|
+
bq query --use_legacy_sql=false --format=csv "<SQL>"
|
|
20
|
+
bq query --use_legacy_sql=false --format=csv < file.sql
|
|
21
|
+
```
|
|
22
|
+
- Deterministic exports: explicit `ORDER BY` (BQ result order is not guaranteed).
|
|
23
|
+
- Cost guard: `--dry_run` to estimate bytes; `--maximum_bytes_billed` to cap.
|
|
24
|
+
|
|
25
|
+
## verb: describe
|
|
26
|
+
```bash
|
|
27
|
+
bq show --schema --format=prettyjson {project}:{dataset}.<table>
|
|
28
|
+
bq show --format=prettyjson {project}:{dataset}.<view> # has the view DDL ("query" field)
|
|
29
|
+
```
|
|
30
|
+
Object inventory: `bq ls {dataset}`; lineage via `INFORMATION_SCHEMA.*` views.
|
|
31
|
+
|
|
32
|
+
## verb: dialect_notes (read by the review skill)
|
|
33
|
+
- **Functions:** `IFNULL`/`COALESCE`, `SAFE_DIVIDE(a,b)` (div-by-zero), `SAFE_CAST`,
|
|
34
|
+
`STRING_AGG` (vs LISTAGG), `ARRAY_AGG`. Standard SQL (`--use_legacy_sql=false`) always.
|
|
35
|
+
- **Sizing:** on-demand (bytes scanned) or slots — partition + cluster columns to prune scans;
|
|
36
|
+
filtering a partition column is the main "warehouse size" lever.
|
|
37
|
+
- **Joins:** type-match with `CAST`/`SAFE_CAST`; mind `STRING` vs `INT64` keys.
|
|
38
|
+
- **Partition pruning** is the analog of clustered-column filtering; `SELECT *` on wide tables is
|
|
39
|
+
the expensive anti-pattern (scans all columns) — list columns.
|
|
40
|
+
- **Dev/deploy:** dev objects in `{dev_dataset}`; promote via scripted `CREATE OR REPLACE`.
|
|
41
|
+
|
|
42
|
+
## gotchas
|
|
43
|
+
- Non-SELECT/DDL ⇒ policy `db_write_requires_approval`.
|
|
44
|
+
- Watch query cost — surface estimated bytes before running anything large.
|