Locutus is the reference implementation for cross-language standard library functions in JavaScript. Every function should be:
- Verified - Tested against actual language runtimes (not just JS unit tests)
- Documented - Clear examples, edge cases, and differences from native
- Typed - Full TypeScript definitions
- Modern - ESM,
ES2022dist target, and browser-facing compatibility aligned tobaseline widely available with downstream - Dependency Free - Locutus only has devDependencies for tooling, but zero for consumers
These steps cover the most important maintainer tasks. When you finish the last, start again at step 1.
Note that for any task, it's important to first get ample context. Search past issues, check project goals, review recent commits, and search the codebase. See if the work was already done and whether it fits the project philosophy.
-
Finish any pending work that is still open locally. This can be determined by looking at
docs/prompts/LOG.mdand inspecting the worktree. Update the last iteration if needed according to the rules indocs/prompts/LOG.md, open a new one for the current iteration, updating it with plans, key learinngs, progress as you go. Revise the document if it is in violation of its rules. -
Use
ghto check on pending PRs. First rungh auth statusto understand what our GitHub identity is. Make sure all PRs have reviews by other people than our identity (fixable only when PRs are submitted by others), that PRs pass (fixable only if they were submitted by US), fix what can be fixed, then re-check next iteration. If all is green, merge. LLMs should refrain from commenting on PRs, but deep reviews on PRs by others are allowed. -
Check GitHub Security separately from issues/PRs:
- inspect repository security advisories and dependency/vulnerability alerts
- use concrete commands, not memory:
gh auth status gh api repos/locutusjs/locutus/security-advisories --paginate --jq 'map(.state) | group_by(.) | map({state: .[0], count: length})' gh api repos/locutusjs/locutus/security-advisories --paginate --jq 'map(select(.state=="triage")) | map({ghsa_id, summary, severity, created_at})' gh api graphql -f query='query { repository(owner:"locutusjs", name:"locutus") { vulnerabilityAlerts(first: 100, states: OPEN) { nodes { number createdAt securityVulnerability { package { name ecosystem } advisory { ghsaId summary severity } vulnerableVersionRange } } } } }'
- distinguish between:
- published historical advisories (record/history)
- open advisory triage work
- automated dependency alerts
- do not trust automated reports blindly; verify:
- whether the affected package is actually in our dependency tree
- whether it affects the published runtime library or only build/test/website tooling
- whether the vulnerable path is realistically reachable in our usage
- whether there is a narrow upstream or transitive remediation available
- prefer the smallest honest response:
- fix and release if runtime/package users are affected
- fix without release if it is website/build-only
- dismiss/close with a precise rationale if the report is not a real Locutus vulnerability
- when in doubt, preserve a high bar for package-level advisories; parity semantics or caller misuse are not automatically GHSA-worthy
-
Triage issues. Confirm repro, decide scope, and say no when needed to protect project goals (see
## Vision,README.md,CHANGELOG.md, andwebsite/source/about.md). LLMs should refrain from commenting on Issues. -
To continuously modernize the project, revise the Backlog/Roadmap in
CHANGELOG.md. Don't forget about the website, which lives in this repo and is deployed via GHA. Check off items and/or move them into releases as appropriate. -
Before any new product work, audit upstream discovery and tracked scope. The flow is:
- run
corepack yarn discover:upstream-surface <language>to materialize the raw canonical catalog from runtime/docs/source - inspect the raw diff and fix discovery first if it over- or under-shoots
- run
corepack yarn fold:upstream-surface <language>when the discovered catalog looks right and you want to accept it into the tracked snapshot YAML - run
corepack yarn audit:upstream-scope <language>to compare tracked scope against raw canonical discovery - use
docs/upstream-surface-scope.ymlas the explicit audit/planning contract for tracked scope, not as a discovery input - if official namespaces are missing from tracked scope, broaden scope first
- if a namespace is too broad, either narrow/exclude it at the source layer or keep it with a broad inventory default after folding
- only resume product work once raw discovery is trustworthy and the tracked target surface for the chosen area is explicit and sane
- run
-
Decide an issue to work on. Before starting, check: What areas have received attention in the last 5 iterations? Prioritize neglected areas. Balance time across: verification (all languages), modernization, TypeScript, website, dependencies.
It could come from:
- a security concern
- the Backlog/Roadmap in
CHANGELOG.md(balance across different items) - a verified GitHub issue
- a PR failure
- upgrading outdated dependencies, checking release notes, taking care of the potential migration, leveraging new capabilities
- unfinished business
Do what is most important and impactful first. First search what is already available, and what we can already re-use, even if it takes a little refactoring. Define what a successful outcome looks like and how you'll validate it (tests, browser checks, screenshots for design changes, or a working migration). This is imperative: no changes without validation. Anything that can't be validated should not be PR'ed or merged.
-
NEVER commit directly to
main. Always create or re-use a goal-oriented branch:git checkout [-]b feat/descriptive-goal # or fix/, chore/, docs/Exceptions:
CORE_MAINTAINER.md,CHANGELOG.md, anddocs/prompts/LOG.mdcan be pushed directly to main. -
Log the plan in
docs/prompts/LOG.md. Work can span multiple iterations on the same branch. -
Start implementing. Make incremental commits as you go.
-
Create a PR only when you've made significant progress (not after each small change):
- Expansion: ~10-15% coverage increase or ~10+ functions
- Verification/Refactoring: 10+ functions fixed or complete a coherent unit
- Bug fixes/security: Individual PRs are fine for discrete issues
Before creating the PR:
- Validate the work (tests, browser checks, etc.)
- Run
yarn check - Update documentation if needed
- For new functions: Check if semantic equivalents exist in other languages and update
src/rosetta.yml - For website changes: After merge, verify the live site at https://locutus.io using Playwright MCP
-
Release recently merged PRs that contain new/changed functions (not just build tools, tests, or docs).
- Before tagging, classify the release using
CONTRIBUTING.md#versioningand include a one-line rationale inCHANGELOG.md.
- Before tagging, classify the release using
-
Log iteration results in
docs/prompts/LOG.md. -
→ Back to step 1
- Zero tolerance: failing tests, Biome errors, unverified implementations (eventually).
- Acceptable warnings: LGPL code (
src/php/_helpers/_bc.js,src/php/bc/*) that can't be modified; intentionaleval/new Functionwithbiome-ignore+ explanation; style warnings in complex algorithms. - Keep one plan: update existing docs (like
CHANGELOG.mdandCORE_MAINTAINER.md) instead of creating new plans.
- Always use branches: Never push to
maindirectly. Create a branch, open a PR, let CI run, then merge. This applies even for "small fixes" - they often aren't. - Verify against reality: unit tests aren't enough; run actual PHP/Go/Python/Ruby/C when possible.
- Don't duplicate infrastructure: check
src/_util/before creating new tools. - Document in the right place: LICENSE, README, SPDX headers, not just issues.
- Biome unsafe fixes can break code: always test after auto-fix.
eval()is sometimes necessary: suppress with explanation, don't fight it.- Batch related work: Accumulate related changes before creating a PR. For expansion, aim for 10+ functions per PR to avoid noise.
- Rosetta Stone mappings: When adding functions, check
src/rosetta.ymlfor semantic equivalents (e.g., PHPstrtolower↔ Rubydowncase↔ GoToLower). This enables cross-language discovery on the website.