Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .agent/skills/tdd-flow/skill.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ triggers:

## Workflow Steps
1. **Red Phase:** Write ONE failing test. Explain the failure. **STOP.**
- Requirement: All tests generated in this phase must adhere to the Test Expectations defined in the ai_instruction file (specifically: No mocking, real HTTP requests, and semantic validation).
- Requirement: All tests generated in this phase must follow the API contract and testing requirements in `AGENTS.md` (specifically: no mocking, real HTTP requests for endpoint coverage and integration tests, and semantic validation).
2. **Green Phase:** Write the simplest possible implementation to pass that specific test. **STOP.**
3. **Refactor Phase:** Suggest improvements to the implementation. Do not change tests.

## Constraint
- Do not jump to Step 2 until the user confirms Step 1 passes (or fails correctly).
- Do not jump to Step 2 until the user confirms Step 1 passes (or fails correctly).
33 changes: 26 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
All AI agents (Codex, Copilot, Antigravity) must adhere to the rules defined in .agent/rules/ and this file.
# Agent Instructions

# Project Standards & Agent Behavior
All AI agents (Codex, Copilot, Antigravity) must follow this file and the rules in `.agent/rules/`.

- **Primary Workflow:** We use the `tdd-flow` skill for all new feature development.
- **Test Style:** Focus on behavior-driven assertions. No mocking.
- **Anti-Pattern Guardrail:** Do not "hallucinate" implementation for skipped tests. If a test is ignored, the underlying code must remain untouched.
- **Language/Framework:** JavaScript/TypeScript with Jest for testing.
- **Spec-Strictness:** When generating tests for the SDK, only assert properties explicitly defined in the OpenAPI specification provided. Do not invent "common sense" validations that are not codified in the schema. Call out any ambiguities or gaps in the spec for human review instead of making assumptions.
## Project standards

- The project uses JavaScript/TypeScript and Jest.
- Use the `tdd-flow` skill for feature implementation and bug fixes.
- Preserve existing implementation when a test is skipped. Do not implement behavior inferred from ignored tests.
- Focus tests on observable behavior. Do not use mocks.

## API contract

- The [Mailinator OpenAPI specification](https://github.com/manybrain/mailinatordocs/blob/main/openapi/mailinator-api.yaml) is the source of truth for supported API behavior.
- Only implement or assert properties and validation rules explicitly defined by the specification. Report ambiguities or gaps for human review instead of filling them with assumptions.
- A request class generally maps to one OpenAPI `operationId` and belongs in the module matching that operation's tag.
- Mailinator API request paths must use the `/api/v2/` prefix.
- Export new request classes and response types from both the module's `index.ts` and `src/index.ts`.
- Use the `AUTHORIZATION` constant for authenticated requests. Requests that do not require a token must implement `RequestWithoutToken`.
- Do not remove deprecated or undocumented endpoints without explicit confirmation.

## Testing and verification

- Endpoint coverage and integration tests must make real HTTP requests; do not use request-mocking tools.
- Assertions must validate contract-defined response semantics rather than mere existence.
- After implementation, run `npx tsc --noEmit` and `npm test`.

See [`docs/openapi-alignment.md`](docs/openapi-alignment.md) for the SDK architecture, OpenAPI gap-analysis workflow, and implementation checklist.
184 changes: 0 additions & 184 deletions AI_INSTRUCTIONS.md

This file was deleted.

2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ See [EXAMPLES.md](EXAMPLES.md) for more code examples on how to use the client.

## Development

See [OpenAPI alignment](docs/openapi-alignment.md) for the SDK architecture, specification gap-analysis workflow, and implementation checklist.

#### Build tests

* `npm test`
Expand Down
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ROADMAP

- [x] Add AI_INSTRUCTIONS.md that explain the link between this client and the OpenAPI specification. That is the source of truth for this repo.
- [x] Document the relationship between this client and the OpenAPI specification, the source of truth for this repository.
- [x] Pull examples out of README.md add to separate file(s). Make sure the examples are clear and accurate.
- [x] Add section on how to publish updates to npm to README.md
- [x] Add depreciation warning to endpoints that exist here and not in the OpenAPI specification.
Expand Down
114 changes: 114 additions & 0 deletions docs/openapi-alignment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# OpenAPI Alignment

The [Mailinator OpenAPI specification](https://github.com/manybrain/mailinatordocs/blob/main/openapi/mailinator-api.yaml) is the source of truth for this SDK. Use the [raw specification](https://raw.githubusercontent.com/manybrain/mailinatordocs/main/openapi/mailinator-api.yaml) for automated or machine-assisted analysis.

Agent behavior and non-negotiable repository rules live in [`AGENTS.md`](../AGENTS.md). This document describes the SDK architecture and the repeatable process for comparing it with the specification.

## SDK architecture

The directories under `src/` correspond to logical Mailinator API areas and, where applicable, OpenAPI tags. API operations use request classes named `{Operation}Request.ts`.

Each request class generally maps to one OpenAPI `operationId` and:

- implements `Request<ResponseType>`, or `RequestWithoutToken<ResponseType>` when authentication is not required;
- constructs a URL under `https://api.mailinator.com/api/v2/`;
- uses `MailinatorRestClient` to execute the appropriate HTTP method;
- uses types in the corresponding module for request and response schemas; and
- is exported by both the module's `index.ts` and the root `src/index.ts`.

Requests are executed through `MailinatorClient`:

```typescript
const client = new MailinatorClient("api_token");
const request = new GetInboxRequest("domain.com", "inbox_name");
const response = await client.request(request);
```

## Gap-analysis workflow

### 1. Read the specification

From every entry under `paths`, record:

- HTTP method and full path;
- `operationId`;
- tag;
- path and query parameters;
- request body schema; and
- response schemas and status codes.

Also record the top-level tags and component schemas used by those operations.

### 2. Catalog the SDK

For every `*Request.ts` under `src/`, record:

- class and module name;
- HTTP method;
- resolved URL template;
- constructor inputs and query parameters;
- request and response types;
- module and root exports; and
- deprecation status.

Inspect the implementation rather than inferring behavior from the class name.

### 3. Compare both sides

Report these categories separately:

1. **Missing SDK operations:** specification operations with no corresponding request class.
2. **SDK-only operations:** request classes with no matching specification path and method. Identify deprecated classes separately; flag other cases for clarification.
3. **Path or method mismatches:** including any URL that does not use `/api/v2/`.
4. **Parameter gaps:** contract-defined path, query, or body fields missing from the request class, plus SDK fields absent from the contract.
5. **Schema gaps:** missing or inconsistent request and response types.
6. **Export gaps:** implemented classes or types missing from a module index or `src/index.ts`.

Do not treat an operation as matching based only on a similar name. Match its HTTP method and normalized path, then verify its `operationId` and schemas.

### 4. Prepare an implementation plan

Before changing code, list:

- new request classes grouped by module;
- path and method corrections;
- parameter changes;
- model or schema changes;
- export updates; and
- deprecated or undocumented endpoints requiring a human decision.

Do not remove deprecated or undocumented endpoints without confirmation.

### 5. Implement using existing conventions

Use the closest current request class as the template. In particular:

- use `/api/v2/` in Mailinator API paths;
- use `AUTHORIZATION` from `src/Constants.ts` rather than a string literal;
- use `RequestWithoutToken` for unauthenticated requests;
- add `/** @deprecated ... */` above deprecated class declarations; and
- update the module index and `src/index.ts` for every public addition.

Follow the `tdd-flow` skill and the testing requirements in `AGENTS.md` for feature implementation and bug fixes.

### 6. Verify

Run:

```bash
npx tsc --noEmit
npm test
```

For new or corrected requests, also verify that the resolved HTTP method, path, parameters, and contract-defined response semantics match the specification. Integration tests must use real Mailinator endpoints and must not use request-mocking tools.

## Stable conventions

| Convention | Requirement |
| --- | --- |
| Version source | Use the `version` field in `package.json`; `src/Constants.ts` reads it dynamically. |
| Authentication | Use the `AUTHORIZATION` constant from `src/Constants.ts`. |
| Unauthenticated requests | Implement `RequestWithoutToken`. |
| API prefix | Use `/api/v2/`. |
| Deprecation | Add a JSDoc `@deprecated` marker and require confirmation before removal. |
| Public exports | Export through the module index and `src/index.ts`. |
4 changes: 3 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module.exports = {
transform: {'^.+\\.ts?$': 'ts-jest'},
transform: {
'^.+\\.ts?$': ['ts-jest', {tsconfig: 'tsconfig.test.json'}]
},
testEnvironment: 'node',
setupFiles: ['dotenv/config'],
testRegex: '/tests/.*\\.(test|spec)?\\.(ts|tsx)$',
Expand Down
Loading