@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.
- package/.claude-template/agents/README.md +5 -0
- package/.claude-template/commands/README.md +5 -0
- package/.claude-template/hooks/README.md +5 -0
- package/.claude-template/settings.json +18 -0
- package/README.md +81 -0
- package/bin/sync-claude.js +33 -0
- package/claude/CLAUDE.md +6 -0
- package/conventions/javascript-formatting.md +55 -0
- package/conventions/jsx-fragments.md +29 -0
- package/conventions/nested-objects.md +15 -0
- package/conventions/property-shorthand.md +18 -0
- package/conventions/rules.md +8 -0
- package/conventions/transactions.md +34 -0
- package/package.json +27 -0
|
@@ -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.
|
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}`)
|
package/claude/CLAUDE.md
ADDED
|
@@ -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
|
+
}
|