@drawbridge/drawbridge-agents 0.1.55 → 0.1.58
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.
- package/.claude-template/skills/drawbridge-asana-comment/SKILL.md +107 -0
- package/.claude-template/skills/drawbridge-asana-ship-handoff/SKILL.md +28 -53
- package/claude/CLAUDE.md +2 -0
- package/conventions/humanized-copy.md +2 -0
- package/conventions/rules.md +6 -0
- package/conventions/verification.md +39 -0
- package/package.json +1 -1
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: drawbridge-asana-comment
|
|
3
|
+
description: Use before posting ANY comment to an Asana task — ship handoffs, answers, status notes, questions. Enforces scannable lists of actions over paragraphs, plain correctly-named things, a mandatory review before posting, and the humanizer pass.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Write an Asana comment
|
|
7
|
+
|
|
8
|
+
Every comment posted to Asana goes through this skill. No exceptions for length, urgency, or
|
|
9
|
+
"it's just a quick note". Posting is publishing. A teammate reads it, acts on it, and cannot
|
|
10
|
+
unread a wrong one.
|
|
11
|
+
|
|
12
|
+
Four rules, in order of how often they get broken.
|
|
13
|
+
|
|
14
|
+
## 1. Lists and actions, not paragraphs
|
|
15
|
+
|
|
16
|
+
There is no word count. Length is not the problem, shape is. Structure it so the reader can
|
|
17
|
+
scan it and act.
|
|
18
|
+
|
|
19
|
+
**The default shape:**
|
|
20
|
+
|
|
21
|
+
- One line on what changed, in plain past tense.
|
|
22
|
+
- A list of what to do and what to expect. One step per line, each one something they can
|
|
23
|
+
actually do or check.
|
|
24
|
+
- Anything that would otherwise look wrong to them, as its own line.
|
|
25
|
+
|
|
26
|
+
Use prose only for something a list would distort, like a one-sentence cause. Never write three
|
|
27
|
+
paragraphs where four bullets would do.
|
|
28
|
+
|
|
29
|
+
**Every line earns its place.** Cut it if it is:
|
|
30
|
+
|
|
31
|
+
- The investigation narrative. They want the outcome, not how you got there.
|
|
32
|
+
- File names, commit SHAs, function names, branch names. They are verifying behaviour.
|
|
33
|
+
- Anything restating what they already told you.
|
|
34
|
+
- Anything that would not change what they do next.
|
|
35
|
+
|
|
36
|
+
**Completeness beats brevity.** Include every scenario to retest, any setup gotcha, and
|
|
37
|
+
anything in the result that would look wrong without warning. A second comment correcting or
|
|
38
|
+
completing the first is the real failure. Structure is what keeps a complete comment readable,
|
|
39
|
+
so restructure before you cut content.
|
|
40
|
+
|
|
41
|
+
**The stop test:** if it does not fit on a phone screen without scrolling, restructure it. Do
|
|
42
|
+
not trim facts to hit a length.
|
|
43
|
+
|
|
44
|
+
## 2. Use normal words and name things correctly
|
|
45
|
+
|
|
46
|
+
Write for the person reading it, not for the repo.
|
|
47
|
+
|
|
48
|
+
- **No internal jargon.** If the term lives in our docs and not in their message, replace it
|
|
49
|
+
with a plain description. Runbook, backfill, cascade, manifest, provider row, seam, capped,
|
|
50
|
+
hydrate all read as noise to someone testing a button. If you must use one, say what it is
|
|
51
|
+
the first time.
|
|
52
|
+
- **Name things by their real name.** The screen, the button, the plan, the setting, exactly as
|
|
53
|
+
the interface labels them. Not your paraphrase, not the variable name. If the button says
|
|
54
|
+
Send, write Send.
|
|
55
|
+
- **Quote user-facing copy exactly**, so they can match it against what is on screen.
|
|
56
|
+
- Use their words for their bug. If they called it a prize notification, it is a prize
|
|
57
|
+
notification, not a lead-facing transactional send.
|
|
58
|
+
|
|
59
|
+
## 3. Review before posting, always
|
|
60
|
+
|
|
61
|
+
Never post a first draft. Read it back against this list:
|
|
62
|
+
|
|
63
|
+
- Is it a scannable list of actions, or did it drift back into paragraphs?
|
|
64
|
+
- **Is every claim verified?** Each factual statement must be something you checked in this
|
|
65
|
+
session: a test you ran, a deploy you confirmed live, a value you read. Anything you merely
|
|
66
|
+
believe gets cut or marked unverified. A wrong comment is worse than a thin one and costs
|
|
67
|
+
them a retest.
|
|
68
|
+
- Any jargon they have not used themselves?
|
|
69
|
+
- Does it open with `<a data-asana-gid="<their gid>"/>` so they are actually notified?
|
|
70
|
+
- Would this need a follow-up comment? Fix that now.
|
|
71
|
+
|
|
72
|
+
Then show the user the final text and get a go-ahead before posting, unless they have already
|
|
73
|
+
said to proceed. After posting, read the comment back (`get_task` with comments) and confirm
|
|
74
|
+
the mention expanded and the formatting survived. Asana silently flattens some markup.
|
|
75
|
+
|
|
76
|
+
## 4. Run it through `humanizer`
|
|
77
|
+
|
|
78
|
+
Required by `conventions/humanized-copy.md`, no exceptions for length. It must not touch the
|
|
79
|
+
mention markup, quoted interface copy, or any concrete step. If a pass makes an instruction
|
|
80
|
+
vaguer, keep the original for that line. If humanizer is unavailable, say so and do not post.
|
|
81
|
+
|
|
82
|
+
## Sound like a teammate
|
|
83
|
+
|
|
84
|
+
The comment should read as though the person who did the work wrote it in a hurry, because that
|
|
85
|
+
is what a good one is.
|
|
86
|
+
|
|
87
|
+
- **Plain past tense about what you did.** "Fixed on dev." Not "the fix has been implemented"
|
|
88
|
+
or "this has now been addressed".
|
|
89
|
+
- **No throat-clearing.** No "Thanks for flagging this", "Great catch", "Just wanted to let you
|
|
90
|
+
know", "I hope this helps", "Let me know if you have questions".
|
|
91
|
+
- **No hedging stack.** Not "this should now potentially resolve". Either it works and you saw
|
|
92
|
+
it work, or you say what you did not check.
|
|
93
|
+
- **Own a mistake in one line and move on.** "I had this wrong, it only affects email." Not a
|
|
94
|
+
paragraph of explanation.
|
|
95
|
+
- **Say what you did not test.** Being straight about a gap is what makes the rest credible.
|
|
96
|
+
- **Ask a real question when you need an answer**, at the end, as a question. Do not bury it.
|
|
97
|
+
- **Bold almost nothing.** If everything is bold, nothing is.
|
|
98
|
+
- **No emoji** unless the thread already uses them.
|
|
99
|
+
|
|
100
|
+
## Notes
|
|
101
|
+
|
|
102
|
+
- Plain prose goes in `text`. Use `html_text` for a mention or a list. Allowed tags are
|
|
103
|
+
`<body> <strong> <em> <code> <ol> <ul> <li> <a> <blockquote> <pre>` only.
|
|
104
|
+
- The `<a data-asana-gid="..."/>` form expands to a real @-mention. Reassignment alone is easy
|
|
105
|
+
to miss, so mention the person even when you also reassign.
|
|
106
|
+
- If the Asana MCP is not connected, stop and say so. Never describe a comment as posted when
|
|
107
|
+
it was not.
|
|
@@ -1,69 +1,44 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: drawbridge-asana-ship-handoff
|
|
3
|
-
description: Use when a feature has shipped (merged to develop) against an Asana task — reassigns the task back to its last commenter, posts a concise
|
|
3
|
+
description: Use when a feature has shipped (merged to develop) against an Asana task — reassigns the task back to its last commenter, posts a concise retest summary, and sets the due date to today.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Asana ship handoff
|
|
7
7
|
|
|
8
8
|
Hand a shipped feature back to whoever last commented on its Asana task, with everything they
|
|
9
|
-
need to retest. Use this right after merging
|
|
9
|
+
need to retest. Use this right after merging to `develop` (which deploys to dev).
|
|
10
10
|
|
|
11
11
|
## Inputs
|
|
12
12
|
|
|
13
|
-
- The Asana task URL or ID
|
|
14
|
-
|
|
15
|
-
- The change you shipped
|
|
13
|
+
- The Asana task URL or ID. Ask for it if it isn't obvious from the branch, PR, or
|
|
14
|
+
conversation. Do not guess.
|
|
15
|
+
- The change you shipped.
|
|
16
16
|
|
|
17
17
|
## Steps
|
|
18
18
|
|
|
19
|
-
1. **Load the task.** `
|
|
20
|
-
2. **Find the
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
wrong (an odd amount, a delay, a cosmetic leftover). A follow-up comment correcting or
|
|
37
|
-
completing this one is the failure this limit exists to prevent, so check the draft for
|
|
38
|
-
omissions *before* trimming words.
|
|
39
|
-
|
|
40
|
-
**Open with an @-mention of the reassignee** — use `html_text` and start the body with
|
|
41
|
-
`<a data-asana-gid="<their user gid>"/>` (Asana expands it into a proper mention). A
|
|
42
|
-
comment without a mention may notify no one; reassignment alone is easy to miss.
|
|
43
|
-
4. **Run the draft through `humanizer`.** A real teammate reads this, and generated-sounding
|
|
44
|
-
prose reads as effort nobody spent. Invoke the `humanizer` skill on the drafted body: it
|
|
45
|
-
strips the AI tells — inflated claims, hedging, stock transitions, "it's worth noting",
|
|
46
|
-
restating the ask twice.
|
|
47
|
-
|
|
48
|
-
It pulls in the same direction as the word limit above, so apply it *before* the final
|
|
49
|
-
trim and re-check the result against both rules. Two things it must not touch: the
|
|
50
|
-
`<a data-asana-gid="..."/>` mention (leave the markup exactly as-is) and any concrete
|
|
51
|
-
detail from the Retest steps — if a pass makes the steps vaguer, keep the original wording.
|
|
52
|
-
5. **Confirm before writing.** This posts to an external system. Show the user the chosen
|
|
53
|
-
assignee and the drafted comment and get a go-ahead, unless they've told you to proceed
|
|
54
|
-
without asking.
|
|
55
|
-
6. **Apply** (on approval):
|
|
56
|
-
- `asana_update_task` — set `assignee` to the last commenter's gid and `due_at` to the
|
|
57
|
-
current date/time (ISO 8601).
|
|
58
|
-
- `asana_create_task_story` — post the comment.
|
|
59
|
-
7. **Report** the task URL, who it was assigned to, and confirm the due date was updated.
|
|
19
|
+
1. **Load the task.** `get_task` with the gid from the URL.
|
|
20
|
+
2. **Find the reassignee.** `get_task_stories`, filter to stories whose `resource_subtype` is
|
|
21
|
+
`comment_added`, take the most recent one's `created_by`. Do not hardcode a person. If there
|
|
22
|
+
are no comments, the task's creator is the fallback, but say so and confirm it.
|
|
23
|
+
3. **Write the comment with `drawbridge-asana-comment`.** That skill owns the shape, the naming
|
|
24
|
+
rules, the humanizer pass, claim verification and the read-back. Do not restate its rules
|
|
25
|
+
here or work around them.
|
|
26
|
+
|
|
27
|
+
What this comment specifically must carry: what changed, and if they reported a bug, what
|
|
28
|
+
actually caused it; then the steps to retest and the expected result. Ground the steps in
|
|
29
|
+
the behaviour that changed, not in the diff.
|
|
30
|
+
4. **Apply**, once the user has approved the text:
|
|
31
|
+
- `update_tasks` with `assignee` set to their gid and `due_on` set to today (`YYYY-MM-DD`).
|
|
32
|
+
The MCP cannot set a due *time*, only a date, so do not try to pass `due_at`.
|
|
33
|
+
- `add_comment` with `html_text`.
|
|
34
|
+
5. **Report** the task URL, who it went to, and the due date. Confirm from the tool result, not
|
|
35
|
+
from intent.
|
|
60
36
|
|
|
61
37
|
## Notes
|
|
62
38
|
|
|
63
|
-
-
|
|
64
|
-
|
|
65
|
-
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
haven't been done yet — this skill is the final step of that flow.
|
|
39
|
+
- Keep it QA-facing: what to test and expect. If a sentence only makes sense to someone who has
|
|
40
|
+
read the diff, it does not belong in the comment.
|
|
41
|
+
- Run `drawbridge-ship-feature` instead if the docs and graph updates for this ship have not
|
|
42
|
+
been done yet. This skill is the last step of that flow.
|
|
43
|
+
- If the Asana MCP isn't connected, stop and say so. Never describe a handoff that did not
|
|
44
|
+
happen.
|
package/claude/CLAUDE.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
@../conventions/cross-repo-contracts.md
|
|
3
3
|
@../conventions/karpathy-guidelines.md
|
|
4
4
|
@../conventions/rules.md
|
|
5
|
+
@../conventions/verification.md
|
|
5
6
|
@../conventions/javascript-formatting.md
|
|
6
7
|
@../conventions/nested-objects.md
|
|
7
8
|
@../conventions/jsx-fragments.md
|
|
@@ -19,3 +20,4 @@
|
|
|
19
20
|
@../conventions/git-branching.md
|
|
20
21
|
@../conventions/graphify.md
|
|
21
22
|
@../conventions/testing.md
|
|
23
|
+
@../conventions/workflow-step-naming.md
|
|
@@ -18,6 +18,8 @@ descriptions — engineer-facing text follows the code conventions instead.
|
|
|
18
18
|
Rules when running it:
|
|
19
19
|
|
|
20
20
|
- Run humanizer BEFORE posting/committing the copy, not after someone flags it.
|
|
21
|
+
- **Asana comments go through the `drawbridge-asana-comment` skill**, which runs the humanizer
|
|
22
|
+
pass for you along with the brevity cap and the read-back. Do not hand-roll a comment.
|
|
21
23
|
- It must not change facts, numbers, steps, or expected results — if a pass makes concrete
|
|
22
24
|
instructions vaguer, keep the original wording for those parts.
|
|
23
25
|
- Leave markup intact (Asana mention tags, links, placeholders like `{name}`).
|
package/conventions/rules.md
CHANGED
|
@@ -12,3 +12,9 @@
|
|
|
12
12
|
This is not a style preference, it is the difference between advice and noise. Asserting a limitation that isn't real sends the reader to check your work, and asserting two implementations are identical when one carries a field the other drops ships a regression. Both have happened.
|
|
13
13
|
|
|
14
14
|
In practice: before claiming a component can't do something, read the component. Before calling two implementations equivalent, read both ends to end. Before proposing a new endpoint or field to work around a gap, confirm the gap exists in the code rather than in your sample of it.
|
|
15
|
+
|
|
16
|
+
6. Prove absence before you claim it, and name the space you searched. "Nothing writes this field", "that isn't documented anywhere", "no caller does this" — claims of that shape cost far more to establish than they look. Reading one file proves what that file does; it can never prove what every other file doesn't. Search the whole space the claim covers — every repo, the built `dist/` as well as the source, `drawbridge-docs/user-stories/` as well as the code, and the tests — then put the space in the sentence: "no writer across the family, source and dist" rather than "nothing writes it".
|
|
17
|
+
|
|
18
|
+
Why: the reader cannot see where you stopped looking. A bare "it doesn't exist" reads as settled, and by the time the thing turns up — documented under an older name, written by a manifest in another package — work has already been built on top of it. Naming the search space turns an unfalsifiable claim into one that can be checked in seconds.
|
|
19
|
+
|
|
20
|
+
Three traps that have actually caused this. A counter incremented from a manifest in `drawbridge-utils` while the search only covered `drawbridge-sync`. A workflow step documented under a name the product had since changed, so searching for the product's label found nothing. A key assembled at runtime (`'totals.' + field`) that no search for the literal will ever match — when a claim depends on a name, check whether the name is ever built rather than written.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Verify before you assert
|
|
2
|
+
|
|
3
|
+
Every rule here was written after a confident, wrong statement reached Darren. They share one shape: the reasoning was sound and the input was never checked. Sound reasoning on an unchecked input is the most expensive kind of wrong, because nothing downstream looks suspicious.
|
|
4
|
+
|
|
5
|
+
## Never state a number you did not measure
|
|
6
|
+
|
|
7
|
+
A measurement in a sentence — a count, a total, "none in the last 30 days" — may only be emitted when the underlying field is actually present. Gate on `value != null` before the claim and say nothing when it is absent.
|
|
8
|
+
|
|
9
|
+
`|| 0` on an unmeasured field manufactures a fact. In drawbridge-growth it reached three surfaces at once: the task queue, profile embeddings, and outreach drafts telling paying customers they had done nothing, all from a field no connected database was filling.
|
|
10
|
+
|
|
11
|
+
The same applies to prose. "This is faster", "most callers do X", "that's a small table" are measurements. Measure them or drop them.
|
|
12
|
+
|
|
13
|
+
## Walk the flow before saying it works
|
|
14
|
+
|
|
15
|
+
Tests passing, lint clean and a green build are not evidence that a screen works. Three bugs in a row survived all three and were found by clicking: a `.then()` chained off a react-query `mutate()` (which returns undefined), colour swatches handed `{ hex, name }` objects where CSS wanted a string, and a screen in a question flow that asked nothing.
|
|
16
|
+
|
|
17
|
+
Before reporting a feature as working, run the path a person takes through it. If the runtime makes that hard, that is a reason to fix the harness, not to skip the walk.
|
|
18
|
+
|
|
19
|
+
## Fetch before claiming what is on a branch
|
|
20
|
+
|
|
21
|
+
Before asserting what is or isn't on `origin/develop` or `origin/main`, run `git fetch` **in that repo**. Fetching one family repo does not refresh the others, and grepping a stale `origin/develop` returns stale content with no warning.
|
|
22
|
+
|
|
23
|
+
In a multi-repo check, fetch every repo you will cite, in one batch, first. Treat an `origin/<branch>` read as evidence only if the fetch happened in this session. "Repo A ships a write that repo B's schema rejects" is exactly the shape a stale ref produces — re-fetch, or read the live database, before reporting it.
|
|
24
|
+
|
|
25
|
+
## Quote vendor documentation, do not recall it
|
|
26
|
+
|
|
27
|
+
When writing against a vendor's API, open its documentation and quote each literal as you write it: authorize url, token url, revoke url, API base, required headers, scope names, auth scheme. Then re-read the finished file against the docs as a separate pass, paying most attention to the lines written first.
|
|
28
|
+
|
|
29
|
+
Klaviyo's `authorize` host was written from memory as `a.klaviyo.com` — the API host — while the browser-facing url is `www.klaviyo.com`. The docs were fetched five times that session for the values that felt uncertain, and never for the one already written. Confidence is not verification, and the values never doubted are the ones that reach a user unchecked.
|
|
30
|
+
|
|
31
|
+
Pin the API **version** too. Documentation defaults to `latest`; a repo pins something older, and a field that exists in `latest` may not exist in the pinned version — or may be deprecated there when it is current in `latest`.
|
|
32
|
+
|
|
33
|
+
## Check the shape you are consuming, not the one you expect
|
|
34
|
+
|
|
35
|
+
Before importing, confirm the symbol is actually exported by that package's entry point. Before chaining off a wrapper's return value, confirm what it returns. Both have shipped inert code that compiled cleanly.
|
|
36
|
+
|
|
37
|
+
## A build that exits 0 is not a build that ran
|
|
38
|
+
|
|
39
|
+
Confirm the build produced its real output — a route table, an emitted bundle, a written artifact — rather than trusting the exit code. `drawbridge-app-web` aborts on a missing environment variable and still exits 0, which is a "successful" build that compiled nothing.
|
package/package.json
CHANGED