Skip to content

add v1 of freighter extension best practices skill#2687

Open
leofelix077 wants to merge 4 commits intomasterfrom
feature/freighter-best-practices-skill
Open

add v1 of freighter extension best practices skill#2687
leofelix077 wants to merge 4 commits intomasterfrom
feature/freighter-best-practices-skill

Conversation

@leofelix077
Copy link
Copy Markdown
Collaborator

Skill Eval: freighter-best-practices — Benchmark Report

Date: 2026-04-09
Iterations: 1
Repo: stellar/freighter
Model: Claude Opus 4.6

Summary

on further passes both get close to 100%, as Claude picks up automatically on the rules and the entry points

Metric With Skill Without Skill Delta
Pass rate 81.5% 74.1% +7.4pp

Assertion Results (aggregated across 1 iterations)

anti-patterns-refactor

# Assertion With Skill Without Skill
1 Adds error handling with captureException (no empty catch block) 1/1 (100%) 0/1 (0%)
2 Changes from default export to named export 1/1 (100%) 1/1 (100%)
3 Changes from function declaration to arrow function expression 1/1 (100%) 1/1 (100%)
4 Extracts inline onClick to useCallback 1/1 (100%) 0/1 (0%)
5 Moves enrichedTokens computation to createSelector or useMemo 1/1 (100%) 1/1 (100%)
6 Replaces Function with proper typed callback 1/1 (100%) 1/1 (100%)
7 Replaces any[] with proper TypeScript types 1/1 (100%) 1/1 (100%)
8 Replaces array index key with stable unique identifier 1/1 (100%) 1/1 (100%)
9 Replaces chrome.runtime.sendMessage with sendMessageToBackground 1/1 (100%) 1/1 (100%)
10 Uses double quotes in string literals 1/1 (100%) 1/1 (100%)
11 Wraps list item in React.memo() 1/1 (100%) 0/1 (0%)
12 Wraps user-facing strings in t() 1/1 (100%) 1/1 (100%)

architecture-redux-duck

# Assertion With Skill Without Skill
1 Background store hydration saves to chrome.storage.session on changes 0/1 (0%) 0/1 (0%)
2 Does NOT add a new React context for data sharing 1/1 (100%) 1/1 (100%)
3 Does NOT put view-local filter state in Redux 1/1 (100%) 1/1 (100%)
4 No module-level mutable state in background code 1/1 (100%) 0/1 (0%)
5 Uses ActionStatus enum for async operation tracking 1/1 (100%) 1/1 (100%)
6 Uses Redux (createSlice/createAsyncThunk) for the cross-cutting dApp connections... 1/1 (100%) 1/1 (100%)
7 Uses useReducer with RequestState pattern for view-local filtering/sorting 1/1 (100%) 1/1 (100%)

architecture-state-decision

# Assertion With Skill Without Skill
1 All user-facing error messages wrapped in t() 1/1 (100%) 1/1 (100%)
2 Named export (not default export) 1/1 (100%) 1/1 (100%)
3 No magic strings - error codes referenced via enum values 1/1 (100%) 1/1 (100%)
4 Provides both English (en) and Portuguese (pt) translations for all error messag... 0/1 (0%) 0/1 (0%)
5 Uses enum for Horizon error codes (not union type or plain strings) 1/1 (100%) 1/1 (100%)
6 Uses t() with interpolation for dynamic values, not template literals 1/1 (100%) 1/1 (100%)
7 Uses unknown (not any) for untyped error inputs 1/1 (100%) 1/1 (100%)

code-style-scss

# Assertion With Skill Without Skill
1 File extension is .scss (not .css or .module.css) 1/1 (100%) 1/1 (100%)
2 No hardcoded color values (hex, rgb, etc.) 1/1 (100%) 1/1 (100%)
3 No raw pixel values for spacing/sizing 0/1 (0%) 0/1 (0%)
4 Uses BEM naming convention with kebab-case block names 0/1 (0%) 0/1 (0%)
5 Uses pxToRem() for size values instead of raw pixels 1/1 (100%) 1/1 (100%)
6 Uses var(--sds-clr-*) design system color tokens 1/1 (100%) 1/1 (100%)

code-style-todo-magic

# Assertion With Skill Without Skill
1 No module-level mutable state for caching (if background, uses chrome.storage) 0/1 (0%) 0/1 (0%)
2 Numeric literals like cache duration and multiplier are SCREAMING_SNAKE_CASE con... 1/1 (100%) 1/1 (100%)
3 TODO comment references a GitHub issue number: // TODO(#1234): description 1/1 (100%) 0/1 (0%)
4 Uses ?? for nullish coalescing instead of
5 Uses named export 1/1 (100%) 1/1 (100%)
6 Uses unknown or proper types instead of any 1/1 (100%) 1/1 (100%)

err-handling-bg-handler

# Assertion With Skill Without Skill
1 Adds new entry to SERVICE_TYPES enum 0/1 (0%) 0/1 (0%)
2 Calls captureException for unexpected errors 1/1 (100%) 0/1 (0%)
3 Does NOT call captureException for expected errors like contract-not-found 1/1 (100%) 1/1 (100%)
4 Handler function never throws - always returns structured response object 1/1 (100%) 1/1 (100%)
5 Registers handler with case statement in the message listener 0/1 (0%) 0/1 (0%)
6 Returns { error: string } for error cases, not thrown exceptions 1/1 (100%) 1/1 (100%)
7 Uses sendMessageToBackground from popup side, NOT direct chrome.runtime.sendMess... 1/1 (100%) 0/1 (0%)

err-handling-thunk

# Assertion With Skill Without Skill
1 Calls captureException from Sentry for unexpected errors 1/1 (100%) 1/1 (100%)
2 Does NOT use console.error for error reporting 1/1 (100%) 0/1 (0%)
3 Error handling uses rejectWithValue with both instanceof Error and fallback bran... 1/1 (100%) 1/1 (100%)
4 Uses createAsyncThunk from Redux Toolkit 1/1 (100%) 1/1 (100%)
5 Uses createSelector for any derived state 1/1 (100%) 1/1 (100%)
6 Uses createSlice with ActionStatus enum for loading/success/error states 1/1 (100%) 1/1 (100%)
7 Uses interface for state shape, not type alias 1/1 (100%) 1/1 (100%)
8 Uses named exports, not default exports 1/1 (100%) 1/1 (100%)

i18n-settings

# Assertion With Skill Without Skill
1 All user-facing strings wrapped in t() with interpolation syntax, not template l... 1/1 (100%) 1/1 (100%)
2 Boolean prop uses is/has/should prefix 1/1 (100%) 0/1 (0%)
3 Does NOT use React.FC pattern 1/1 (100%) 1/1 (100%)
4 Event handler props use on prefix, internal handlers use handle prefix 1/1 (100%) 1/1 (100%)
5 Provides both English (en) and Portuguese (pt) translation entries 1/1 (100%) 1/1 (100%)
6 SCSS uses BEM naming and var(--sds-clr-*) tokens 1/1 (100%) 1/1 (100%)
7 Uses enum (not union type) for auto-lock timeout options 1/1 (100%) 1/1 (100%)
8 Uses enum (not union type) for currency options 1/1 (100%) 1/1 (100%)
9 Uses interface for component props shape 1/1 (100%) 1/1 (100%)

messaging-service-type

# Assertion With Skill Without Skill
1 Adds value to SERVICE_TYPES enum (not creating a new enum) 1/1 (100%) 1/1 (100%)
2 Creates handler function in handlers/ directory 1/1 (100%) 1/1 (100%)
3 Does NOT call browser.runtime.sendMessage or chrome.runtime.sendMessage directly... 1/1 (100%) 1/1 (100%)
4 Handler returns structured response object, never throws 1/1 (100%) 1/1 (100%)
5 Popup sends via sendMessageToBackground() helper 1/1 (100%) 1/1 (100%)
6 Registers handler in listener with case statement 1/1 (100%) 1/1 (100%)
7 Response uses domain-specific fields for success, { error: string } for failure 0/1 (0%) 1/1 (100%)

performance-list

# Assertion With Skill Without Skill
1 All user-facing text wrapped in t() 1/1 (100%) 0/1 (0%)
2 CSS uses var(--sds-clr-*) design tokens, not hardcoded colors 1/1 (100%) 1/1 (100%)
3 Callbacks passed as props wrapped in useCallback 1/1 (100%) 1/1 (100%)
4 List item component is wrapped in React.memo() 1/1 (100%) 1/1 (100%)
5 No inline arrow functions inside .map() or list render 0/1 (0%) 0/1 (0%)
6 SCSS uses BEM naming convention with kebab-case 1/1 (100%) 1/1 (100%)
7 Uses createSelector for derived/computed values from Redux state 1/1 (100%) 0/1 (0%)
8 Uses pxToRem() instead of raw pixel values 0/1 (0%) 1/1 (100%)
9 Uses stable unique identifiers as keys, not array index 1/1 (100%) 1/1 (100%)

performance-selectors

# Assertion With Skill Without Skill
1 Does NOT compute derived state inline in the component 0/1 (0%) 0/1 (0%)
2 Does not add a new React context for cross-slice data - uses Redux selectors 1/1 (100%) 1/1 (100%)
3 Objects/arrays created for props are wrapped in useMemo 0/1 (0%) 1/1 (100%)
4 Uses ?? (nullish coalescing) instead of for fallback values
5 Uses createSelector to derive data across multiple Redux slices 1/1 (100%) 1/1 (100%)
6 Uses interface for props shape 0/1 (0%) 1/1 (100%)
7 Uses template literals (not string concatenation) for any string building 1/1 (100%) 1/1 (100%)

security-ext-msg

# Assertion With Skill Without Skill
1 Adds new entry to EXTERNAL_SERVICE_TYPES enum (not SERVICE_TYPES) 1/1 (100%) 1/1 (100%)
2 All user-facing strings wrapped in t() from useTranslation 1/1 (100%) 1/1 (100%)
3 Background handler validates message type against enum 1/1 (100%) 0/1 (0%)
4 Background handler validates sender origin 1/1 (100%) 1/1 (100%)
5 Content script only forwards messages with valid EXTERNAL_SERVICE_TYPES 0/1 (0%) 1/1 (100%)
6 Handler returns structured response, never throws 1/1 (100%) 1/1 (100%)
7 Popup uses navigateTo with ROUTES enum for navigation 0/1 (0%) 0/1 (0%)
8 Uses double quotes in all string literals 1/1 (100%) 1/1 (100%)

security-key-export

# Assertion With Skill Without Skill
1 Calls captureException for unexpected errors during encryption/decryption 1/1 (100%) 0/1 (0%)
2 Does NOT use non-null assertion (!) on key material - handles undefined explicit... 1/1 (100%) 1/1 (100%)
3 Does not store any decrypted secrets in chrome.storage.local 1/1 (100%) 1/1 (100%)
4 Never logs private keys, mnemonics, or decrypted key material 1/1 (100%) 1/1 (100%)
5 Reads decrypted key material from chrome.storage.session (not chrome.storage.loc... 0/1 (0%) 1/1 (100%)
6 Returns structured response object, never throws 1/1 (100%) 1/1 (100%)
7 Uses unknown or proper types instead of any for error handling 1/1 (100%) 1/1 (100%)

testing-thunk

# Assertion With Skill Without Skill
1 Creates test store with configureStore() 1/1 (100%) 1/1 (100%)
2 Dispatches thunks and asserts via store.getState() 1/1 (100%) 1/1 (100%)
3 Test file located in tests/ directory 1/1 (100%) 1/1 (100%)
4 Test file uses .test.ts extension, not .spec.ts 1/1 (100%) 1/1 (100%)
5 Tests error path verifying captureException is NOT called for expected errors 0/1 (0%) 0/1 (0%)
6 Tests success path with proper state assertions 1/1 (100%) 1/1 (100%)
7 Tests unexpected error path verifying captureException IS called 0/1 (0%) 0/1 (0%)
8 Uses jest.requireMock for typed mock access 1/1 (100%) 0/1 (0%)

Copilot AI review requested due to automatic review settings April 9, 2026 16:47
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a first version of a “Freighter best practices” skill/doc bundle to codify engineering conventions for the Freighter extension repo (architecture, messaging, i18n, security, testing, etc.), plus a lightweight repo entry-point index.

Changes:

  • Add llms.txt as a quick link index into key Freighter docs.
  • Add docs/skills/freighter-best-practices/ skill definition + reference guides (code style, architecture, messaging, security, testing, etc.).
  • Update CLAUDE.md “AI Agent Context” documentation.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
llms.txt Adds a concise index of key docs/entry points for agents and contributors.
docs/skills/freighter-best-practices/SKILL.md Defines the skill and links to reference guides by concern.
docs/skills/freighter-best-practices/references/testing.md Documents Jest/Playwright testing conventions and commands.
docs/skills/freighter-best-practices/references/security.md Documents key storage, message validation, CSP, and common security pitfalls.
docs/skills/freighter-best-practices/references/performance.md Captures performance guidance and common optimization patterns/anti-patterns.
docs/skills/freighter-best-practices/references/messaging.md Documents popup/background/content-script message flows and handler patterns.
docs/skills/freighter-best-practices/references/i18n.md Documents react-i18next usage, locale files, and translation build workflow.
docs/skills/freighter-best-practices/references/git-workflow.md Documents branch/commit/PR expectations and release workflow overview.
docs/skills/freighter-best-practices/references/error-handling.md Documents thunk + background handler error-handling patterns and Sentry usage.
docs/skills/freighter-best-practices/references/dependencies.md Documents workspace layout and dependency placement/upgrade workflow.
docs/skills/freighter-best-practices/references/code-style.md Documents Prettier/ESLint expectations and TS/React style conventions.
docs/skills/freighter-best-practices/references/architecture.md Summarizes runtime contexts, state management patterns, and key extension conventions.
docs/skills/freighter-best-practices/references/anti-patterns.md Lists common pitfalls (deps suppression, non-null assertions, module state in bg, etc.).
CLAUDE.md Updates AI-agent context and repo conventions summary.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

CLAUDE.md Outdated
Comment on lines +124 to +126
1. `pretty-quick --staged` — Prettier on staged files
2. `lint-staged` — ESLint fix on staged `.ts`/`.tsx`
3. Translation build — auto-generates `extension/src/popup/locales/` files
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pre-commit hook description here doesn’t match the repo’s actual Husky hook. .husky/pre-commit runs ./.husky/addTranslations.sh and pretty-quick --staged only; it does not run lint-staged, and the translation build happens before formatting. Please update this section to reflect the current hook (or update the hook to match this doc).

Suggested change
1. `pretty-quick --staged`Prettier on staged files
2. `lint-staged` — ESLint fix on staged `.ts`/`.tsx`
3. Translation buildauto-generates `extension/src/popup/locales/` files
1. `./.husky/addTranslations.sh`translation build that auto-generates
`extension/src/popup/locales/` files
2. `pretty-quick --staged`Prettier on staged files

Copilot uses AI. Check for mistakes.
CLAUDE.md Outdated
- **Translations:** All user-facing strings wrapped in `t()` from
`react-i18next`. Run `yarn build:extension:translations` to generate keys. See
`extension/LOCALIZATION.MD`.
- **Imports:** External packages first, then internal. ESLint enforces ordering.
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line says ESLint enforces import ordering, but the current eslint.config.js does not configure an import/order (or equivalent) rule—import ordering is a convention only. Please reword to avoid implying it’s enforced.

Suggested change
- **Imports:** External packages first, then internal. ESLint enforces ordering.
- **Imports:** External packages first, then internal; follow this convention
consistently.

Copilot uses AI. Check for mistakes.

```typescript
// CORRECT
t("Send {{amount}} XLM", { amount: "100" })// WRONG
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example code block merges the CORRECT and WRONG examples onto the same line (...)// WRONG), which makes the snippet confusing and syntactically invalid. Split this into separate lines and clearly label the WRONG example as its own line/block.

Suggested change
t("Send {{amount}} XLM", { amount: "100" })// WRONG
t("Send {{amount}} XLM", { amount: "100" });
// WRONG

Copilot uses AI. Check for mistakes.
Merge CLAUDE.md into AGENTS.md: add documentation link index at the top
(llms.txt style), full quick reference table, repository structure,
architecture details, conventions, and known complexity from CLAUDE.md.
Best practices entry points table kept at the bottom.

Remove CLAUDE.md and update llms.txt to point to AGENTS.md.
Rewrite AGENTS.md as the single AI agent entry point:
- Add glossary section with domain-specific terminology
- Add documentation link index (replaces llms.txt)
- Remove sections that duplicate best-practices reference files
  (code style details, branch conventions, PR instructions)
- Keep unique context: env setup, repo map, architecture orientation,
  security alert list, known complexity/gotchas, pre-submission checklist
- Delete llms.txt (content absorbed into AGENTS.md)
- Delete CLAUDE.md (already removed in previous commit)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants