Install
$ agentstack add skill-xobotyi-cc-foundry-javascript ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
JavaScript
Clarity is the highest JavaScript virtue. If your code requires a comment to explain its control flow, rewrite it.
JavaScript rewards explicit, readable code. Prefer boring patterns that are easy to understand over clever tricks that save characters.
References
- Functions, closures, composition → [
${CLAUDE_SKILL_DIR}/references/functions.md] — Arrow function examples,
closure patterns, early return, parameter destructuring
- Async patterns, error handling, concurrency → [
${CLAUDE_SKILL_DIR}/references/async.md] — Promise.all/race/any
examples, cancellation, custom error classes, for-await
- Objects, arrays, iteration, Map/Set → [
${CLAUDE_SKILL_DIR}/references/objects-and-arrays.md] — Iteration
decision table, destructuring patterns, immutable updates, generators
- ES modules, imports, barrel files → [
${CLAUDE_SKILL_DIR}/references/modules.md] — Import ordering, barrel file
rationale, directory import pitfalls, dynamic imports
- JSDoc typing, full tag catalog → [
${CLAUDE_SKILL_DIR}/references/jsdoc.md] — Full tag reference (@callback,
@template, @enum), type assertions, class modifiers
- General JS idioms and edge cases → [
${CLAUDE_SKILL_DIR}/references/idioms.md] — Variable/naming examples,
equality coercion table, modern syntax patterns
Variables and Declarations
constby default. Useletonly when reassignment is required. Nevervar.constprevents reassignment, not mutation. Objects and arrays declared withconstcan still be mutated.- Block scope only.
let/constare block-scoped;varis function-scoped and hoists — this causes bugs in loops
and conditionals.
- One declaration per line. Never chain
const a = 1, b = 2. - Group declarations.
constfirst, thenlet.
Naming
| Entity | Style | Examples | | --------------------------- | -------------------------------- | ----------------------------------- | | Variables, functions | camelCase | userName, fetchData | | Classes, constructors | PascalCase | UserService, HttpClient | | True compile-time constants | SCREAMINGSNAKECASE | MAX_RETRIES, API_BASE_URL | | Private fields/methods | # prefix (class) | #count, #validate() | | Booleans | is/has/can/should prefix | isValid, hasAccess | | File names | kebab-case or camelCase | user-service.js, userService.js |
- SCREAMINGSNAKECASE is for true constants only — values known at compile time, never computed at runtime. A
variable holding a function return value uses camelCase.
- Descriptive names.
userCountnotn. Short names (i,x) only in tiny scopes (loop indices, simple arrow
callbacks).
- Accepted abbreviations:
url,id,err,ctx,req,res— universally understood. Avoid all others. - No redundant context.
car.makenotcar.carMake. - Consistent vocabulary. Use the same word for the same concept throughout a codebase —
getUser()everywhere, not
getUserInfo() / getClientData() / getCustomerRecord().
Equality and Safety
- Always
===and!==. Never==except forvalue == null(checks bothnullandundefined). ??over||for defaults —||treats0,"",falseas falsy.?.for optional access. Don't overuse — missing data you expect should throw, not silently returnundefined.- Know the falsy values:
false,0,-0,0n,"",null,undefined,NaN. Everything else is truthy,
including [], {}, and "0".
Ternary Operator
- One-liners or split-per-branch only. Ternaries are acceptable in two forms:
```js // OK — fits on one line const label = isActive ? 'Active' : 'Inactive';
// OK — each branch on its own line const label = isActive ? buildActiveLabel(user) : buildInactiveLabel(user); ```
Any ternary that doesn't fit one of these two patterns must be rewritten as if/else or early return.
- Nested ternaries are banned. No exceptions. Use
if/else, early returns, or a lookup object.
Modern Syntax
- Template literals for string interpolation: `
Hello, ${name}`. Don't use template literals for strings
without interpolation — use plain quotes.
- Spread for copies:
{ ...obj }and[...arr]. NeverObject.assign. - Rest parameters to collect remaining:
const { id, ...rest } = user. - Shorthand properties:
{ name, age }not{ name: name, age: age }. Group shorthand properties at the top of
object literals.
- Computed property names:
{ [key]: value, [${key}Date]: new Date() }. - Logical assignment operators:
opts.timeout ??= 5000(assign if nullish),opts.name ||= "default"(assign if
falsy), opts.handler &&= wrap(opts.handler) (assign if truthy).
Functions
- Arrow functions for callbacks and anonymous functions. Use function declarations only when hoisting or
this
binding is needed.
- Prefer parentheses around arrow function parameters even for single params — smaller diffs when adding/removing
parameters.
- Implicit return for single expressions (no braces). Explicit return (braces) for multi-statement bodies.
- Arrow functions capture lexical
this— they do NOT have their ownthis. Never use arrow functions as object
methods or on prototypes.
- Destructured options for 3+ parameters. Self-documenting and order-independent.
- Default parameters over
||or manual checks. Defaults are evaluated left-to-right and can reference earlier
params.
- Rest parameters over
argumentsobject.argumentsis array-like, not a real Array. - Early return. Guard clauses first, happy path flat. Reduce nesting.
- One function, one job. If the name contains "and", split it.
- Keep functions under ~30 lines. Extract helpers. Use composition over complex branching.
- Prefer pure functions (same input = same output, no side effects). Isolate side effects (DOM, network, logging) —
don't hide them inside data transformations.
- Closures retain references to outer variables, not copies. Be cautious with large objects captured unintentionally
— they won't be garbage collected until the closure is released.
Async
async/awaitover.then()chains for sequential operations.- Always
awaitpromises. Missingawait= floating promise = silent failures. return awaitonly insidetryblocks where you need to catch the awaited error. Otherwise justreturn promise
— no need for async wrapper.
Promise.allfor independent parallel work. Rejects on first rejection.Promise.allSettledwhen all results matter regardless of individual failures.Promise.racefor timeouts.Promise.anyfor fallbacks (rejects only when ALL reject).- Avoid sequential awaits in loops. Use
Promise.all(items.map(...))for parallel. Use a concurrency limiter (e.g.
p-map) for large arrays.
- Throw
Errorobjects, never strings or plain objects — strings lose stack traces. - Custom error classes when callers need to distinguish errors: extend
Error, setthis.name, add context
properties.
- Never swallow errors. Every
catchmust handle, rethrow, or report. Emptycatchblocks hide bugs.
console.log(err) alone is not handling.
- Let errors propagate to a top-level handler when possible. Don't wrap every
awaitintry/catch— only where
you need to handle at that level.
- Attach
.catch()to non-awaited promise chains. Unhandled rejections crash Node.js. Fire-and-forget:
fetchData().catch(reportError).
- Only use
new Promise()to wrap callback-based APIs. Most async code should compose existing promises with
async/await.
AbortControllerfor cancellable async operations: pass{ signal }tofetchand other APIs.for await...offor async iterables (streams, async generators).
Modules
- ES modules only.
import/exportfor all new code. CommonJS (require) is legacy — use only when runtime
requires it.
- Named exports over default exports. Default exports cause inconsistent naming across importers. Exception: default
exports acceptable when required by framework convention (Next.js pages, Remix routes).
- Don't export mutable
letbindings. Export accessor functions instead:export function getCount()not
export let count.
- Imports at the top, grouped with blank lines: built-in (
node:fs), external (express), internal (./utils). - Always include file extensions in import paths —
"./user.js", not"./user". Extensionless imports vary across
runtimes.
- No directory imports. Import from the file directly, not from a folder that resolves to
index.js. - No barrel files in subdirectories.
index.jsre-exports create indirection and hurt tree-shaking. Acceptable only
as a standalone package entry point where the runtime can enforce the boundary via package.json exports.
- No circular dependencies. Extract shared code to a third module, merge tightly coupled modules, or use dependency
injection.
- No wildcard re-exports. Explicit re-exports only — wildcards bypass tree-shaking.
- Merge imports from the same module into a single statement.
- Namespace imports (
import * as dateFns) for large modules (5+ items). Prefer named imports when importing fewer
than ~5 items.
- Dynamic imports (
import()) for code splitting and lazy loading: routes loaded on navigation, large conditional
dependencies, feature flags.
- One concern per module. If a module exports unrelated functionality, split it.
- Side-effect imports (
import "./polyfill.js") should be rare. Document why.
Objects and Arrays
- Literal syntax.
{}and[], nevernew Object()/new Array(). - Use method shorthand on objects:
greet() { }notgreet: function() { }. - Spread for copies.
{ ...obj }and[...arr]. Prefer overObject.assign. - Destructure to extract properties. Prefer parameter destructuring.
- Dot notation for static properties, brackets for dynamic:
user.namevsuser[dynamicKey]. Object.hasOwn(obj, key)instead ofobj.hasOwnProperty(key).- Functional array methods (
map,filter,find,some,every,flatMap,reduce) over imperative loops for
data transformation.
- Always return in
map,filter,reducecallbacks. Array.from(arrayLike)for array-like objects (not spread).Array.from(iterable, mapFn)instead of
[...iterable].map(mapFn) — avoids intermediate array.
- Don't mutate inputs. Return new objects/arrays. Immutable update patterns: add
[...arr, item], remove
arr.filter(...), update arr.map(...).
for...offor side-effect loops. Neverfor...inon arrays.- Return objects for multiple values, not arrays — callers don't depend on order.
- Never extend built-in prototypes (
Array.prototype,Object.prototype). Use utility functions or subclasses.
Prefer for...of for side-effect loops, Array.prototype methods (.map, .filter, .reduce, .find, .some, .every) for data transforms, for for index-needed loops. See ${CLAUDE_SKILL_DIR}/references/objects-and-arrays.md for the full iteration decision table.
Use Map when keys aren't strings or are user-provided (avoids prototype pollution). Use Set for dedup ([...new Set(items)]). Use generators (function*) for lazy sequences and deferred computation.
Classes
- ES
classsyntax only. No function constructors or prototype manipulation. #privatefields for encapsulation. Not_convention.- Composition over inheritance. Use
extendsonly for true "is-a" relationships. - No empty constructors. If the constructor only calls
super(), omit it. - Static methods for operations that don't need instance state.
- Methods can return
thisfor fluent/chainable APIs. - Don't force classes when plain functions and objects suffice. A class with one method is a function in disguise.
JSDoc Typing
For pure JavaScript projects that don't use TypeScript, use JSDoc annotations to provide type safety through editor tooling. Enable // @ts-check at file top or checkJs in jsconfig.json.
Core tags: @type, @param, @returns, @typedef (with @property), @template. See ${CLAUDE_SKILL_DIR}/references/jsdoc.md for the full tag catalog including @callback, @enum, class modifiers, and type import syntax.
JSDoc Best Practices
- Annotate public API boundaries — exported functions, classes, module-level variables. Internal code often needs
fewer annotations; types flow from context.
- Prefer inline TypeScript syntax in JSDoc types:
{string | number}over{(string|number)}. - Use
@typedeffor shared shapes — define once near file top or intypes.js. - Don't annotate the obvious — if
const x = 5is clearly a number, skip@type.
Doc Comments
Doc comments (/** */) are API documentation, not code comments — the "no comments" default does not apply.
Every exported function, class, and module-level constant gets a doc comment. Include @param, @returns, @throws for non-trivial signatures. Describe behavior and intent, not implementation.
When modifying an exported symbol's behavior or signature, update its doc comment in the same edit.
Application
When writing JavaScript code:
- Apply all conventions silently — don't narrate each rule being followed.
- If an existing codebase contradicts a convention, follow the codebase and flag the divergence once.
When reviewing JavaScript code:
- Cite the specific violation and show the fix inline.
- Don't lecture or quote the rule — state what's wrong and how to fix it.
Bad review comment:
"According to best practices, you should use const instead of let
when the variable is never reassigned."
Good review comment:
"`let` -> `const` — `config` is never reassigned."
Code Navigation — LSP Required
A typescript-language-server LSP server is configured for all JS/TS file types (.js, .jsx, .ts, .tsx, .mjs, .cjs, .mts, .cts). Always use LSP tools for code navigation instead of Grep or Glob. LSP understands module resolution, type inference, scope rules, and project boundaries — text search does not.
Tool Routing
- Find where a function/class/variable is defined →
goToDefinition— Resolves imports, re-exports, aliases - Find all usages of a symbol →
findReferences— Scope-aware, no false positives from string matches - Get type signature, docs, or return types →
hover— Instant type info without reading source files - List all exports/symbols in a file →
documentSymbol— Structured output vs grepping for
function/class/export
- Find a symbol by name across the project →
workspaceSymbol— Searches all modules - Find implementations of an interface →
goToImplementation— Knows the type system - Find what calls a function →
incomingCalls— Precise call graph across module boundaries - Find what a function calls →
outgoingCalls— Structured dependency map
Grep/Glob remain appropriate for: text in comments, string literals, log messages, TODO markers, config values, env vars, CSS classes, file name patterns, URLs, error message text.
When spawning subagents for JS/TS codebase exploration, instruct them to use LSP tools. Subagents have access to the same LSP server.
Integration
The coding skill governs workflow; this skill governs JavaScript implementation choices. For TypeScript projects, the typescript skill e
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: xobotyi
- Source: xobotyi/cc-foundry
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.