Skip to content

Commit 8bdb698

Browse files
authored
Strengthen agent rules from error details porting learnings (#12)
1 parent 04062f0 commit 8bdb698

5 files changed

Lines changed: 147 additions & 3 deletions

File tree

.agent/rules/libraries.mdc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
description: Guidelines for choosing libraries over hand-rolled solutions.
3+
scope: all source files
4+
enforcement: strict
5+
globs: ["packages/**/src/**/*.ts"]
6+
---
7+
8+
# Libraries over Hand-Rolling
9+
10+
Prefer established ecosystem libraries over hand-rolled solutions for common
11+
tasks like validation, parsing, and serialization. For example, use Zod for
12+
runtime type validation instead of writing manual type guards and validation
13+
helpers.
14+
15+
When proposing a library, justify the choice with concrete references (docs,
16+
API examples). Do not assert that something is "idiomatic" or "standard"
17+
without pointing to where that convention is documented.
18+
19+
## Current Libraries
20+
21+
| Task | Library | Notes |
22+
| ----------------------------- | ------- | ------------------------------ |
23+
| Runtime type validation / JSON unmarshalling | Zod | Used for API wire-format parsing |

.agent/rules/porting.mdc

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ or reword them. Translate Go `//` comments to JSDoc (`/** */`) format for
2020
exported symbols, but keep the full content including multi-paragraph
2121
explanations and examples.
2222

23+
**Do not add documentation beyond what the Go SDK has.** If a Go type or
24+
function has no doc comment, the TypeScript version should not have one either.
25+
Do not invent explanations, add `@packageDocumentation` summaries, or expand
26+
on what Go provides.
27+
2328
```go
2429
// OutOfRange means the operation was attempted past the valid range.
2530
// E.g., seeking or reading past end of file.
@@ -52,3 +57,54 @@ TypeScript:
5257

5358
Each Go package that is separately importable should be a separate directory
5459
with its own `index.ts` and a corresponding subpath export in `package.json`.
60+
61+
## Naming
62+
63+
Names in the TypeScript implementation must be idiomatic TypeScript. Do not
64+
reference the source language in variable, function, or type names.
65+
66+
```typescript
67+
// Good — describes what the schema does.
68+
const nullishString = z.string().nullish().transform(v => v ?? '');
69+
70+
// Bad — references Go in the name.
71+
const goString = z.string().nullish().transform(v => v ?? '');
72+
```
73+
74+
## Tests
75+
76+
Port **all** test cases from the Go SDK. Do not selectively skip tests. When a
77+
Go test case cannot be directly ported (e.g. because of a language difference
78+
like `json.RawMessage` vs already-parsed JSON), explain the omission to the
79+
user and get confirmation before skipping.
80+
81+
Use the same test structure as the Go SDK. Go table-driven tests map to
82+
Vitest's `it.each`:
83+
84+
```go
85+
// Go
86+
testCases := []struct{ name string; input int; want int }{
87+
{"positive", 1, 1},
88+
{"zero", 0, 0},
89+
}
90+
for _, tc := range testCases {
91+
t.Run(tc.name, func(t *testing.T) { ... })
92+
}
93+
```
94+
95+
```typescript
96+
// TypeScript equivalent
97+
const testCases: {name: string; input: number; want: number}[] = [
98+
{name: 'positive', input: 1, want: 1},
99+
{name: 'zero', input: 0, want: 0},
100+
];
101+
it.each(testCases)('$name', ({input, want}) => { ... });
102+
```
103+
104+
## Deviations from Go
105+
106+
When the TypeScript implementation must differ from Go (e.g. different function
107+
signatures, different input types, skipped tests), **explain the deviation to
108+
the user** before proceeding. Do not silently change behaviour or add comments
109+
in the code about Go differences — keep the codebase clean of porting
110+
artifacts.

.agent/rules/testing.mdc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,31 @@ describe('PatCredentials', () => {
5353
});
5454
```
5555

56+
## Table-Driven Tests
57+
58+
When multiple test cases share the same business logic and only differ in
59+
input/output data, use table-driven tests with `it.each`. Do not write
60+
separate `it` blocks for each case.
61+
62+
```typescript
63+
// Good — table-driven.
64+
const testCases: {name: string; input: string; want: number}[] = [
65+
{name: 'positive', input: '1', want: 1},
66+
{name: 'zero', input: '0', want: 0},
67+
];
68+
it.each(testCases)('$name', ({input, want}) => {
69+
expect(parse(input)).toBe(want);
70+
});
71+
72+
// Bad — separate blocks with duplicated logic.
73+
it('should parse positive', () => {
74+
expect(parse('1')).toBe(1);
75+
});
76+
it('should parse zero', () => {
77+
expect(parse('0')).toBe(0);
78+
});
79+
```
80+
5681
## Assertions
5782

5883
Use Vitest's `expect` API. Prefer specific matchers over generic ones.

.agent/rules/typescript.mdc

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,10 @@ export default class TokenCache { ... }
8585

8686
### 2.5 Export Discipline
8787

88-
- Only export symbols that are used outside the module.
88+
- Only export symbols that consumers of the package need. Keep implementation
89+
details (internal helpers, parse functions, schemas) unexported. If a symbol
90+
is only used within the package or by tests, do not export it from
91+
`index.ts`.
8992
- Never use `export let`. Use a getter function if the value must change.
9093
- Do not create container classes with only static members. Export individual
9194
constants and functions instead.
@@ -708,7 +711,39 @@ effects in `afterEach` or `afterAll` blocks.
708711

709712
---
710713

711-
## 15. Platform Compatibility
714+
## 15. Code Uniformity
715+
716+
Keep similar code paths uniform. If multiple cases follow the same pattern,
717+
they should all use the same approach. Do not special-case one variant unless
718+
there is a clear, documented reason.
719+
720+
```typescript
721+
// Good — all cases follow the same pattern.
722+
case ERROR_INFO_TYPE: {
723+
const r = errorInfoSchema.safeParse(raw);
724+
if (!r.success) return false;
725+
ed.errorInfo = r.data;
726+
return true;
727+
}
728+
case RETRY_INFO_TYPE: {
729+
const r = retryInfoSchema.safeParse(raw);
730+
if (!r.success) return false;
731+
ed.retryInfo = r.data;
732+
return true;
733+
}
734+
735+
// Bad — one case uses a different approach for no good reason.
736+
case RETRY_INFO_TYPE: {
737+
const parsed = tryParseRetryInfo(raw);
738+
if (parsed === undefined) return false;
739+
ed.retryInfo = parsed;
740+
return true;
741+
}
742+
```
743+
744+
---
745+
746+
## 16. Platform Compatibility
712747

713748
This SDK targets both Node.js (>= 18) and browsers.
714749

AGENTS.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ self-contained and includes its scope, enforcement level, and examples.
5555
| `packages.mdc` | Package scaffolding and conventions |
5656
| `testing.mdc` | Testing conventions |
5757
| `porting.mdc` | Porting code from the Go reference SDK |
58+
| `libraries.mdc` | Library selection over hand-rolling |
5859

5960
## Common Commands
6061

@@ -91,7 +92,11 @@ npm run clean
9192

9293
1. **Read the rules.** Start with `.agent/rules/typescript.mdc`.
9394
2. **Understand existing code.** Read neighbouring files before editing.
94-
3. **Run checks.** After every change run `npm run lint && npm run typecheck`.
95+
3. **Run checks.** After every change run
96+
`npm run format && npm run lint && npm run typecheck`.
9597
4. **Run tests.** Confirm nothing is broken with `npm test`.
9698
5. **Comments are sentences.** Every comment must be a proper sentence ending
9799
with a period.
100+
6. **Back up claims.** When proposing a design decision or asserting a
101+
convention, provide concrete references (documentation, API links). Do not
102+
state something is "idiomatic" or "standard" without evidence.

0 commit comments

Comments
 (0)