This file is for coding agents and new contributors alike. It says where things
are, how to verify a change, and the conventions the code follows. Product
behaviour for the OpenScience agent itself lives in backend/cli/src/agent/prompt/
and backend/cli/AGENTS.md (the instructions the shipped agent reads when it
works inside backend/cli as a project); this file is about the repository.
ARCHITECTURE.md explains how the pieces fit; CONTRIBUTING.md covers the
dev loops and PR expectations; docs/notes/release-process.md is how releases
are cut.
bun run setup # verify Bun, install, embed the workspace UI once
bun run check # format, typecheck, backend + frontend + sdk unit tests
bun run typecheck # turbo, ~5 s warm
bun run --cwd backend/cli test # backend suite with the 15 s per-test timeout
bun test --timeout 15000 ./test/<dir> # one backend directory (from backend/cli)
bun test --timeout 15000 ./test/<dir>/<file>.test.ts -t "<name>"
bun run test:workspace # frontend/workspace unit tests (happy-dom, ~40 s)
bun run test:ui # @synsci/ui unit tests
bun run --cwd frontend/workspace build # the workspace bundle the CLI embeds
./tooling/repo/generate.ts # regenerate the SDK after changing backend/cli/src/serverThings that bite:
- Use the pinned Bun (
packageManagerin package.json). Other versions produce a different install layout and the frozen lockfile fails. - Bare
bun testinbackend/cliuses Bun's 5 s default timeout and fails spuriously; the package script adds--timeout 15000. - Bun treats a bare
test/<dir>argument as a name filter; pass./test/<dir>. frontend/workspaceunit tests live undersrc/; the Playwright specs ine2e/run throughbun run --cwd frontend/workspace test, notbun test.- Generated, gitignored files:
backend/cli/src/web/assets.generated.ts(the embedded UI;bun run setup --webmakes it),src/provider/models-snapshot.ts(written by the build; the runtime falls back to a live fetch), andsrc/skill/bundled.generated.ts(build only). Tests are hermetic and do not need them. - The Fast CI
Testjob runs only the backend tests affected by the diff; the full backend suite, native ownership tests, and the web builds run in Deep CI (gh workflow run deep-ci.yml --ref <branch>, ~5 min).
- Keep things in one function unless composable or reusable.
- Avoid unnecessary destructuring:
obj.aandobj.bkeep context;const { a, b } = objloses it. - Avoid
try/catchwhere a result type or.catch(() => undefined)reads better. - No
any. Rely on inference; annotate exports and anything a reader would otherwise have to look up. - Prefer
const; avoidletplus if/else reassignment (use a ternary or aniife). - Prefer early returns to
else. - Prefer single-word names when one word is precise.
- Use Bun APIs (
Bun.file(),Bun.spawn,$) over Node equivalents. - Comments explain why, not what. Do not narrate a change in a comment.
- Test behaviour, not text. A test that reads a component's source and asserts
substrings is not a test; it is a snapshot of the current markup and it breaks
on every refactor. The only source-reading tests that stay are the
cross-cutting design contracts under
frontend/*/src/styles. - No mocks where the real implementation can run. Fixtures live next to the tests that use them.
- New backend tests go in the
backend/cli/test/<area>directory whose shard they belong to (tooling/repo/test-shards.tsbalances by directory).
backend/cli/src/server→ run./tooling/repo/generate.tsand committooling/sdk.- User-visible behaviour → a line under
UnreleasedinCHANGELOG.mdand, when it changes how something is used, the page infrontend/docs. - A new skill, connector, tool, or plugin → the guide in
docs/notes/adding-*.mdorwriting-a-plugin.mdsays what else must change. - A skill or code taken from another project → its author and license stay
with it:
metadata.upstream*in the skill's frontmatter,backend/cli/skills/ATTRIBUTION.md, andNOTICEfor a new source or license. - Never edit package versions in a PR;
publish.ymlbumps them.
Stable releases are cut from main by the publish workflow after a green
release rehearsal at the same commit; see docs/notes/release-process.md.
Once npm packages for a version are staged, only release infrastructure may
change before publish, or the resume refuses the drift.
Turborepo configuration, task behavior, and CLI commands can vary between installed versions and may differ from your training data. Resolve the turbo package from this file's directory or relevant workspace; in monorepos, it may not be visible from the repository root. For example, run node -p "require.resolve('turbo/package.json')" from a workspace that depends on turbo.
Read docs/README.md inside that installed package first, then read the relevant pages from its docs/ directory before changing Turborepo configuration or commands. Heed deprecation notices. These bundled docs match the installed package version and are available without network access.
This block is written and re-added by turbo before repository-scoped commands when an AI agent is detected. In the Turborepo source repository, its template is defined in crates/turborepo-cli/src/cli/agent_guidance.rs. Removing the managed block while updates are enabled means a later qualifying invocation will add it again. Set "agentGuidance": false in the root turbo.json or turbo.jsonc to opt out; this does not remove an existing block. Keep the block committed with your work to avoid an uncommitted change on the next agent invocation.
