@drawbridge/drawbridge-agents 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ # Managed by @drawbridge/drawbridge-agents
2
+
3
+ Subagent definitions placed here are mirrored into every consumer repo's `.claude/agents/` on `npm run sync`. To add a shared subagent: drop the markdown definition in this directory in `drawbridge-agents`, bump the package version, publish, then `npm run sync` in each consumer.
4
+
5
+ Consumer-local subagents should be added directly to the consumer's `.claude/agents/` with a different filename — the sync mirror only overwrites paths that exist in this template.
@@ -0,0 +1,5 @@
1
+ # Managed by @drawbridge/drawbridge-agents
2
+
3
+ Slash command markdown files placed here are mirrored into every consumer repo's `.claude/commands/` on `npm run sync`. To add a shared command: drop it in this directory in `drawbridge-agents`, bump the package version, publish, then `npm run sync` in each consumer.
4
+
5
+ Consumer-local commands should be added directly to the consumer's `.claude/commands/` with a different filename — the sync mirror only overwrites paths that exist in this template.
@@ -0,0 +1,5 @@
1
+ # Managed by @drawbridge/drawbridge-agents
2
+
3
+ Hook scripts placed here are mirrored into every consumer repo's `.claude/hooks/` on `npm run sync`. To add a shared hook: drop it in this directory in `drawbridge-agents`, bump the package version, publish, then `npm run sync` in each consumer.
4
+
5
+ Consumer-local hooks should be added directly to the consumer's `.claude/hooks/` with a different filename — the sync mirror only overwrites paths that exist in this template.
@@ -0,0 +1,18 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash",
5
+ "Read",
6
+ "Write",
7
+ "Edit",
8
+ "MultiEdit",
9
+ "Glob",
10
+ "Grep",
11
+ "LS",
12
+ "WebFetch",
13
+ "WebSearch",
14
+ "mcp__*",
15
+ "mcp__sentry__find_projects"
16
+ ]
17
+ }
18
+ }
package/README.md ADDED
@@ -0,0 +1,81 @@
1
+ # @drawbridge/drawbridge-agents
2
+
3
+ Shared agent-instruction content for the drawbridge-* monorepo. One canonical source of conventions (rules, code style, patterns) consumed by every drawbridge-* repo's `CLAUDE.md` (and, in future, other agent config files).
4
+
5
+ ## Why this exists
6
+
7
+ Before this package, every drawbridge-* repo carried a byte-identical copy of the same 164-line `CLAUDE.md`. Updating a rule meant editing 13 places and drift was inevitable. Now the canonical content lives here; each repo's `CLAUDE.md` is a thin file of `@` imports.
8
+
9
+ ## Layout
10
+
11
+ ```
12
+ conventions/ ← canonical, agent-neutral content
13
+ rules.md
14
+ javascript-formatting.md
15
+ nested-objects.md
16
+ jsx-fragments.md
17
+ transactions.md
18
+ property-shorthand.md
19
+
20
+ claude/
21
+ CLAUDE.md ← aggregator — @-imports every conventions/*.md
22
+
23
+ .claude-template/ ← mirrored into each consumer repo's .claude/
24
+ settings.json ← shared permissions/env
25
+ hooks/
26
+ agents/
27
+ commands/
28
+
29
+ bin/
30
+ sync-claude.js ← drawbridge-agents-sync — mirrors .claude-template/ → consumer's .claude/
31
+ ```
32
+
33
+ ## Consuming from a drawbridge-* repo
34
+
35
+ 1. Install:
36
+ ```bash
37
+ npm install --save-exact @drawbridge/drawbridge-agents
38
+ ```
39
+
40
+ 2. Replace the repo's `CLAUDE.md` with a thin import file:
41
+ ```markdown
42
+ @./node_modules/@drawbridge/drawbridge-agents/claude/CLAUDE.md
43
+ ```
44
+
45
+ Add any repo-specific rules **above** that import line.
46
+
47
+ 3. (Optional) Import additional narrow conventions as they're added to this package:
48
+ ```markdown
49
+ @./node_modules/@drawbridge/drawbridge-agents/claude/CLAUDE.md
50
+ @./node_modules/@drawbridge/drawbridge-agents/conventions/sync-side-effects.md
51
+ ```
52
+
53
+ 4. Extend the consumer's `npm run sync` to mirror the shared `.claude/` template:
54
+ ```json
55
+ "sync": ". \"$HOME/.nvm/nvm.sh\" && nvm use && npm prune && npm install && npx drawbridge-agents-sync"
56
+ ```
57
+
58
+ On every `npm run sync`, the contents of this package's `.claude-template/` are copied into the consumer's `.claude/`. Paths that exist in the template are **managed** (overwritten on each sync). Anything else in `.claude/` — including `settings.local.json` and any consumer-only hooks/agents/commands — is left untouched.
59
+
60
+ Claude Code's `@` imports cascade — one import line resolves the whole tree under `claude/CLAUDE.md`.
61
+
62
+ ## Updating a rule or shared `.claude/` file
63
+
64
+ 1. Edit the relevant `conventions/<file>.md` or `.claude-template/<path>`.
65
+ 2. Bump `version` in `package.json` (semver: patch for clarification, minor for added rule/file, major for breaking change).
66
+ 3. `npm audit` (per drawbridge-* publishing convention).
67
+ 4. `npm run build` (runs `npm publish`).
68
+ 5. Bump the exact-pin in each consuming repo's `package.json` and `npm run sync`.
69
+
70
+ ## Content map (origin → destination)
71
+
72
+ This package was lifted from the original `CLAUDE.md` that previously lived in every drawbridge-* repo. The mapping:
73
+
74
+ | Original section | File |
75
+ |---|---|
76
+ | `# Rules` (4 numbered rules) | `conventions/rules.md` |
77
+ | `# JavaScript Formatting` (spaces, colons, brackets, commas, semicolons, indentation) | `conventions/javascript-formatting.md` |
78
+ | `## Nested objects must always be expanded across multiple lines` | `conventions/nested-objects.md` |
79
+ | `## JSX Fragments` | `conventions/jsx-fragments.md` |
80
+ | `## Database Transactions` | `conventions/transactions.md` |
81
+ | `## Property shorthand` | `conventions/property-shorthand.md` |
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('fs')
3
+ const path = require('path')
4
+
5
+ const consumerRoot = process.env.INIT_CWD || process.cwd()
6
+ const templateRoot = path.resolve(__dirname, '..', '.claude-template')
7
+ const destRoot = path.join(consumerRoot, '.claude')
8
+
9
+ if (!fs.existsSync(templateRoot)) {
10
+ console.error(`drawbridge-agents-sync: template not found at ${templateRoot}`)
11
+ process.exit(1)
12
+ }
13
+
14
+ const copied = []
15
+
16
+ const mirror = (src, dst) => {
17
+ fs.mkdirSync(dst, { recursive: true })
18
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
19
+ const s = path.join(src, entry.name)
20
+ const d = path.join(dst, entry.name)
21
+ if (entry.isDirectory()) {
22
+ mirror(s, d)
23
+ } else {
24
+ fs.copyFileSync(s, d)
25
+ copied.push(path.relative(consumerRoot, d))
26
+ }
27
+ }
28
+ }
29
+
30
+ mirror(templateRoot, destRoot)
31
+
32
+ console.log(`drawbridge-agents-sync: ${copied.length} file(s) mirrored to ${path.relative(consumerRoot, destRoot) || '.claude'}`)
33
+ for (const p of copied) console.log(` ${p}`)
@@ -0,0 +1,6 @@
1
+ @../conventions/rules.md
2
+ @../conventions/javascript-formatting.md
3
+ @../conventions/nested-objects.md
4
+ @../conventions/jsx-fragments.md
5
+ @../conventions/transactions.md
6
+ @../conventions/property-shorthand.md
@@ -0,0 +1,55 @@
1
+ # JavaScript Formatting
2
+
3
+ ## Spaces inside parentheses
4
+ ```js
5
+ require( 'module' )
6
+ client.db( 'database' )
7
+ for( const item of array )
8
+ ```
9
+
10
+ ## Spaces around colons in object literals
11
+ ```js
12
+ {
13
+ collection : 'organization',
14
+ data : { ... },
15
+ options
16
+ }
17
+ ```
18
+
19
+ ## Spaces inside computed property brackets
20
+ ```js
21
+ array?.[ 0 ]
22
+ object?.[ key ]
23
+ ```
24
+
25
+ ## No trailing commas on last items in objects
26
+ ```js
27
+ {
28
+ first : 'value',
29
+ second : 'value'
30
+ }
31
+ ```
32
+
33
+ ## Semicolons after objects and functions
34
+ ```js
35
+ if( condition ){
36
+
37
+ // ...
38
+
39
+ };
40
+
41
+ const run = async () => {
42
+
43
+ // ...
44
+
45
+ };
46
+ ```
47
+
48
+ ## Indentation
49
+ - Tabs, size 4
50
+ - Blank line after opening brace of functions and control structures
51
+ - LF line endings
52
+ - Trailing newline at end of file
53
+ - Single quotes for strings
54
+
55
+ When adding or removing a wrapper block (e.g. a transaction callback, an `if` block), re-indent all enclosed lines to match the new nesting level. If the indentation shift is large or the block is long, prefer rewriting the whole function with the Write tool rather than using multiple Edit calls.
@@ -0,0 +1,29 @@
1
+ # JSX Fragments
2
+
3
+ Never use the `<></>` shorthand. Always use explicit `<Fragment></Fragment>` with a named import from `react`.
4
+
5
+ ```js
6
+ // Wrong
7
+ import { useState } from 'react';
8
+
9
+ return (
10
+ <>
11
+ <Foo />
12
+ <Bar />
13
+ </>
14
+ );
15
+
16
+ // Correct
17
+ import { Fragment, useState } from 'react';
18
+
19
+ return (
20
+ <Fragment>
21
+ <Foo />
22
+ <Bar />
23
+ </Fragment>
24
+ );
25
+ ```
26
+
27
+ - Add `Fragment` to the existing named `react` import in alphabetical position (capital `F` sorts before lowercase hooks like `use*`).
28
+ - Do not import `React` as a default just to write `<React.Fragment>` — use the named `Fragment` import.
29
+ - Applies to every Next.js app in the drawbridge-* monorepo.
@@ -0,0 +1,15 @@
1
+ # Nested objects must always be expanded across multiple lines
2
+ Never write inline nested objects — always expand across multiple lines:
3
+ ```js
4
+ // Wrong
5
+ { $slice : [ '$frames', i ] }
6
+ { $add : [ i, 1 ] }
7
+
8
+ // Correct
9
+ {
10
+ $slice : [ '$frames', i ]
11
+ }
12
+ {
13
+ $add : [ i, 1 ]
14
+ }
15
+ ```
@@ -0,0 +1,18 @@
1
+ # Property shorthand
2
+
3
+ Use ES6 property shorthand whenever the source variable name matches the target property key. If you'd write `foo : foo`, drop to `foo`.
4
+
5
+ For JSX, when a prop is computed (helper call, ternary, lookup), hoist it to a local `const` named after the prop above the `return`, then reference it via shorthand inside the prop-spread. Gate the conditional render on that same `const`, not on a re-derived expression.
6
+
7
+ ```js
8
+ const src = cdnSrc( image, '100x100', updatedAt );
9
+
10
+ return src ?
11
+ <Image { ...{ alt, src, fill : true, sizes : '40px' } } />
12
+ :
13
+ <Placeholder />;
14
+ ```
15
+
16
+ Not `src : cdnSrc( ... )` inline; not `src : src` once the variable exists; not gating on `image?.sizes?.[ '100x100' ]` when `src` already encodes the same truthiness.
17
+
18
+ CDN image URLs use `cdnSrc( asset, size, timestamp )` from `@drawbridge/drawbridge-utils/cdn`. All three arguments are required — without `timestamp` the URL would never change across uploads and the CDN/browser would serve a stale asset. Pass the asset's own `updatedAt` when it has one, or the parent document's `updatedAt` for embedded assets (e.g. `user.image`). Returns `undefined` if `asset.sizes[ size ]` or `timestamp` is missing.
@@ -0,0 +1,8 @@
1
+ # Rules
2
+ 1. Ask, don't assume. If something is unclear, ask before writing a single line. Never make silent assumptions about intent, architecture, or requirements.
3
+
4
+ 2. Simplest solution first. Always implement the simplest thing that could work. Do not add abstractions or flexibility that weren't explicitly requested.
5
+
6
+ 3. Don't touch unrelated code. If a file or function is not directly part of the current task, do not modify it, even if you think it could be improved.
7
+
8
+ 4. Flag uncertainty explicitly. If you are not confident about an approach or technical detail, say so before proceeding. Confidence without certainty causes more damage than admitting a gap.
@@ -0,0 +1,34 @@
1
+ # Database Transactions
2
+
3
+ Wrap multiple sequential `controller.update`, `controller.create`, or `controller.delete` calls in `controller.transaction` for atomicity. A single write does not need a transaction.
4
+
5
+ ```js
6
+ await controller.transaction( async ( session ) => {
7
+
8
+ const options = { session };
9
+
10
+ await controller.update({
11
+ collection : 'foo',
12
+ data : { ... },
13
+ options,
14
+ query : { id }
15
+ });
16
+
17
+ await controller.create({
18
+ collection : 'bar',
19
+ data : { ... },
20
+ options
21
+ });
22
+
23
+ } );
24
+ ```
25
+
26
+ Rules:
27
+ - Pass `session` to every operation inside the transaction via `options : { session }`
28
+ - When results are needed outside the transaction, `return` them from the callback — do not fold subsequent operations inside just to avoid returning
29
+ - When other options exist (e.g. `bypassDocumentValidation`), spread them: `{ ...options, session }`
30
+ - **Do NOT include `controller.get` or `controller.aggregate` inside a transaction** — reads do not benefit from transaction protection; fetch them before or after
31
+ - **Do NOT include operations on time-series collections inside a transaction** — MongoDB does not support this (`analytic`, `message` are time-series); perform these writes outside the transaction
32
+ - Socket `io.emit` calls must be outside the transaction — extract return values from the callback
33
+ - External side effects (S3, Stripe API, BullMQ) cannot participate in MongoDB transactions — keep them outside
34
+ - Do not wrap large bulk-delete loops in a single transaction — MongoDB has a 60-second timeout
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@drawbridge/drawbridge-agents",
3
+ "version": "0.0.2",
4
+ "description": "Shared agent-instruction content (rules, code style, conventions) for the drawbridge-* monorepo.",
5
+ "license": "UNLICENSED",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "scripts": {
10
+ "sync": ". \"$HOME/.nvm/nvm.sh\" && nvm use && npm prune && npm install",
11
+ "build": "npm publish"
12
+ },
13
+ "bin": {
14
+ "drawbridge-agents-sync": "bin/sync-claude.js"
15
+ },
16
+ "files": [
17
+ "claude",
18
+ "conventions",
19
+ ".claude-template",
20
+ "bin",
21
+ "README.md"
22
+ ],
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/trydrawbridge/drawbridge-agents.git"
26
+ }
27
+ }