agentleFS
Microsoft AzureKnown publisherAzure/Connectors-NodeJS-SDK/.github/copilot-instructions.md

Connectors-NodeJS-SDK

Copilot instructions0 starsChanged 33 days agoMITView on GitHub

This repository contains the lightweight TypeScript SDK for Azure Logic Apps connectors. Code must follow the team's coding conventions. Variable naming rules: One class per file: Use standard async/await: Single line if all parameters fit: Multi-line when needed: Inline comments — use NOTE format: JSDoc documentation — required for all public APIs:

  • Where files are headingNew Copilot instructions files have more rules about branches and pull requests, and fewer about code style.

    Of the Copilot instructions files we read, the 2,336 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.

  • In this repositoryOne other file it gives its agents.

The file

Show its rules and text

We split this copilot-instructions.md into the rules it gives an agent

24 rules. About 1 is common, 12 are distinctive, and 11 are very specific to this project.

  • ≈1

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈12

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 11

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  • could be automatic: a setting could enforce it
  1. Distinctive:

    No empty lines between import groups

    line 25
  2. Distinctive:

    Use complete, unabbreviated English terms for all identifiers

    line 41
  3. Very specific:

    No single-letter variable names, even in lambdas (use item, method, parameter)

    line 42
  4. Very specific:

    No placeholder names (blah, foo, temp, x) — always use meaningful names

    line 43
  5. Very specific:

    Always use async/await, never .then() chains

    line 63
  6. Common:

    Always handle errors with try/catch

    line 64
  7. Distinctive:

    Prefer returning the awaited value

    line 65
  8. Distinctive:

    Single line: if all parameters fit:

    line 79
  9. Distinctive:

    NO empty line between comment and code it describes

    line 113
  10. Distinctive:

    Do NOT comment on the 'what' unless the code is obscure.

    line 115
  11. Very specific:

    Use @param for parameters

    line 130
  12. Very specific:

    Use @remarks for additional context

    line 131
  13. Very specific:

    Use ConnectorError for connector-specific errors

    line 153
  14. Very specific:

    Test naming: descriptive sentence in test() or it() blocks

    line 288
  15. Very specific:

    Use describe() to group related tests

    line 289
  16. Very specific:

    Use async/await in tests, never .then()

    line 290
  17. Very specific:

    Run with npm test or npx jest --config config/jest.config.js --verbose

    line 292
  18. Distinctive:

    Never push directly to main

    line 297
  19. Distinctive:

    Always create PR for review

    line 298
  20. Distinctive:

    Do not expand repository structure with caches, catalogs, or replay scaffolding unless explicitly requested.

    line 304
  21. Very specific:

    If the BPM generator or live Swagger is unavailable, stop and report the blocker.

    line 310
  22. Distinctive:

    Do not delete or recreate a published release tag as a normal retry path.

    line 329
  23. Distinctive:

    If a failed release left only a draft GitHub Release and no package was published, clean up the draft release if needed, then queue the …

    line 335
  24. Distinctive:

    When adding a new generated connector client to the SDK:

    line 351

≈ “Common” is an estimate: at least 1 in 5 of the 3,779 Copilot instructions files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
copilot-instructions.md

Copilot Instructions for azure-logicapps-connector-sdk (TypeScript)

Overview

This repository contains the lightweight TypeScript SDK for Azure Logic Apps connectors. Code must follow the team's coding conventions.

Quick Reference: Coding Style Rules

File Structure

// Copyright (c) Microsoft Corporation.  All rights reserved.

import { ConnectorClientBase } from "../azureConnectors/clientBase";
import { ConnectorError } from "../azureConnectors/connectorError";

export class YourClass {
}

Rules:

  • Copyright header on first line (single-line comment)
  • Imports sorted: external packages first, then relative imports alphabetically
  • No empty lines between import groups

Naming Conventions

ElementRuleExample
ClassesPascalCaseOffice365Client
InterfacesPascalCaseTokenProvider
Methods/functionsverb-noun camelCasegetEmails()
ConstantsUPPER_SNAKE_CASE or PascalCaseDEFAULT_TIMEOUT
Private fieldscamelCase with no prefixprivate readonly connectionUrl: string;
Local variablescamelCase, complete English termsparameter not p, method not m
Lambda parametersUse descriptive namesitems.filter(item => ...) not x => ...

Variable naming rules:

  • Use complete, unabbreviated English terms for all identifiers
  • No single-letter variable names, even in lambdas (use item, method, parameter)
  • No placeholder names (blah, foo, temp, x) — always use meaningful names

File Organization

One class per file:

  • Declare only one exported class per file
  • File name should match the primary export
  • Exception: Related types/interfaces can co-exist if tightly coupled (e.g., a client + its options)

Async/Await Format

Use standard async/await:

const result = await this.httpClient.sendAsync<Response>("GET", url);

Rules:

  • Always use async/await, never .then() chains
  • Always handle errors with try/catch
  • Prefer returning the awaited value

DO NOT:

// Wrong: Promise chains instead of async/await
this.httpClient.sendAsync("GET", url).then(result => { ... });

// Wrong: Unhandled promise
this.httpClient.sendAsync("GET", url);

Method Calls with Multiple Parameters

Single line if all parameters fit:

this.doSomething(param1, param2);

Multi-line when needed:

const result = await this.httpClient.sendAsync<Response>(
    "POST",
    url,
    headers,
    body,
);

Rules:

  • Trailing comma on the last parameter in multi-line calls
  • Each parameter on its own line when breaking

Comments

Inline comments — use NOTE format:

// NOTE(username): Explanation of why this code exists.
const result = doSomething();

Rules:

  • Empty line ABOVE comment (unless first line in block)
  • NO empty line between comment and code it describes
  • Prefix: // NOTE(username): where username is your GitHub username
  • Do NOT comment on the 'what' unless the code is obscure; instead comment on the 'why' when appropriate

JSDoc documentation — required for all public APIs:

/**
 * Processes the incoming request and returns the result.
 * @param request The request to process.
 */
public async process(request: Request): Promise<Response> {

Rules:

  • End descriptions with period
  • Use @param for parameters
  • Use @remarks for additional context

Error Handling

try {
    const response = await this.httpClient.sendAsync<T>("GET", url);
} catch (error) {
    if (error instanceof ConnectorError) {
        console.error(`Connector error: '${error.message}'.`);
        throw;
    }

    throw new Error(`Operation '${operationId}' failed.`);
}

Rules:

  • Wrap inserted values in single quotes in error messages
  • End error messages with period
  • All errors must have descriptive messages — never throw without context
  • Use ConnectorError for connector-specific errors

DO:

throw new Error(`Parameter '${paramName}' cannot be null or empty.`);
throw new ConnectorError(connectorName, `GET ${path}`, statusCode, responseText);

DO NOT:

throw new Error();          // No message
throw new Error("error");   // Non-descriptive

String Comparison

Use case-insensitive comparison when appropriate:

// Correct
str1.toLowerCase() === str2.toLowerCase()

// For exact match
str1 === str2

DO NOT:

str1 == str2   // Loose equality

Spacing and Braces

Empty line after closing brace:

if (condition) {
    doSomething();
}

doSomethingElse();  // Empty line above

NO empty line before closing brace:

// Wrong
if (condition) {
    doSomething();

}

Variable Declaration

Use const by default, let when reassignment is needed:

const items = new Array<string>();
const response = await this.getResponseAsync();
let counter = 0;

DO NOT use var.

Ternary Operators

Put ? and : at START of new line:

const result = condition
    ? valueIfTrue
    : valueIfFalse;

Logical Operators

Put || and && at END of line:

if (value1 === undefined ||
    value2 === undefined ||
    value3 === undefined) {

Access Modifiers

ALWAYS explicit on class members:

public static readonly defaultValue = "default";
private readonly connectionUrl: string;

Class Layout Order

  1. Static fields
  2. Instance fields
  3. Constructor
  4. Properties (getters)
  5. Public methods
  6. Private methods

Patterns to Avoid

Anti-PatternCorrect Pattern
.then() chainsawait with async/await
var declarationsconst or let
any typeSpecific types or unknown
Magic numbersNamed constants
Magic strings (e.g., "type", "object")Named constants
Loose equality (==)Strict equality (===)
Array[0] without checkValidate array length first

Testing

test("methodName should return expected result when given valid input", async () => {
    // Arrange
    const input = createTestInput();

    // Act
    const result = await service.processAsync(input);

    // Assert
    expect(result).toBeDefined();
});

Rules:

  • Test naming: descriptive sentence in test() or it() blocks
  • Use describe() to group related tests
  • Use async/await in tests, never .then()
  • Jest framework with ts-jest preset
  • Run with npm test or npx jest --config config/jest.config.js --verbose

Git Workflow

  • Branch naming: feature/description, fix/description, docs/description
  • Never push directly to main
  • Always create PR for review

Generated Code Ownership — Critical

  • Paired generator/SDK PRs may publish output from the linked active BPM PR. Record its exact source commit and active/unmerged status. Showing the generated outcome does not wait for upstream merge; upstream integration remains a separate final SDK merge gate.
  • Refreshes follow GENERATION.md: fetch live definitions with an explicit subscription/region and a new empty temporary ARMCACHE_PATH. Reviewers make a separate live download; never seed either run from repository fixtures or producer responses.
  • Do not expand repository structure with caches, catalogs, or replay scaffolding unless explicitly requested. Existing Swagger snapshots are test fixtures, not refresh/review inputs. Remove temporary response stores after the run.
  • Capture known response data in semantic variables without redundant aliases or repeated conditions. Execute changed consumers with empty/nonempty results, and exercise actual continuation requests and termination, including an empty first page with a next link.
  • Everything under src/generated/ is owned by the BPM CodefulSdkGenerator. Never hand-edit generated clients, registries, barrel exports, imports, method signatures, error handling, or formatting, even to fix a build, lint, merge, or review failure.
  • When a generated file fails after merging or rebasing main, first compare it with sibling generated files and the generator revision recorded in generation.manifest.json. Runtime contract changes such as renamed errors, response fields, method conventions, and options must be fixed in BPM when the current generator is wrong, then regenerated here from fresh live Swagger.
  • Replace generated files only with generator output. Update generation.manifest.json with the actual generator composition, Swagger hash, and canonical output hash; do not make the manifest legitimize a manual generated-file edit.
  • Hand-authored tests, samples, documentation, and runtime infrastructure may be updated directly to consume a regenerated API.
  • If the BPM generator or live Swagger is unavailable, stop and report the blocker. Do not patch src/generated/ or fall back to cached inputs.

Releasing a New Version

Queue azure-pipelines/library-release.yml with the desired libraryVersion (for example, 1.2.3 or 1.2.3-preview.1). Do not create the release branch or tag manually as the normal release path.

The pipeline creates release/<version>, updates package.json and package-lock.json, pauses for validation, builds the package, tags the release branch as v<version>, creates a draft GitHub release with the .tgz asset, and uploads the artifact to the Azure SDK partner drop after approval.

The prebuild script regenerates src/azureConnectors/sdkInfo.ts from the final package metadata, and prepack rebuilds after any pipeline version change. Do not edit sdkInfo.ts directly.

Re-releasing a Version

Do not delete or recreate a published release tag as a normal retry path. Release tags are part of the supply-chain integrity boundary and are protected by tag rulesets. If a release fails after the tag was pushed, use a new version (for example the next patch version, or a new pre-release such as v1.2.4-preview.1) and release from the current reviewed main commit.

If a failed release left only a draft GitHub Release and no package was published, clean up the draft release if needed, then queue the pipeline with a new version. Deleting or retagging an existing remote tag should be treated as break-glass admin work, not the standard process.

What the Release Workflow Does

  1. Creates and validates the versioned release branch.
  2. Builds and packs the npm package from that branch.
  3. Creates and pushes the v<version> tag.
  4. Creates a draft GitHub release and attaches the .tgz artifact.
  5. Pauses for release-note review.
  6. Uploads the artifact to the Azure SDK partner drop.

Adding a New Connector

When adding a new generated connector client to the SDK:

Steps

  1. Generate the code using the CodefulSdkGenerator CLI from the BPM repo:

    LogicAppsCompiler <outputDir> unused --typescriptDirectClient --connectors=<connector-name>
  2. Verify generated files — {Connector}Extensions.ts lands in src/generated/
  3. Check connectorNames.ts — the new connector constant should be generated in alphabetical order
  4. Check ManagedConnectors.ts — the connector name should appear in AvailableConnectors
  5. Add unit tests — create {connector}Client.test.ts in tests/ following the pattern of existing tests (constructor, mocked API call, error handling)
  6. Update ROADMAP.md — mark the connector as complete in the appropriate phase
  7. Update the connection setup skill — add the connector's API name to the supported list in .github/skills/connection-setup/SKILL.md (Step 2)
  8. Run all tests — npm test must pass with zero failures before committing
  9. Create a PR — reference the GitHub issue (e.g., Closes #9)

Validation checklist

  • Generated file compiles without errors (npm run typecheck)
  • Existing connector tests still pass (no regressions)
  • connectorNames test passes (ConnectorNames ↔ ManagedConnectors sync)
  • New connector tests cover: constructor, mocked success, mocked error, exception properties

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.