For contributors and maintainers

Change the source, then prove the shipped tree.

IdeaForge has no dependencies and no build step. Its architecture keeps interview logic separate from browser APIs, while the test and delivery pipelines exercise the same static files that users receive.

Use the repository references for the sharp edges. This page is the working map, not a second copy of every implementation invariant. Read AGENTS.md for the validation loop, CLAUDE.md for invariants, and the architecture map before a change of any size.

Architecture and boundaries

Source is split by responsibility so most behaviour can run under Node without a DOM, network, real clock, or mocking framework. Dependencies flow from the UI into runtime and core, while browser-facing services sit beside that path.

Directory Owns Boundary
src/core/ Sessions, coverage, prompts, synthesis, exports, backup format validation, and other pure decisions. No DOM, network, clock, or randomness.
src/runtime/ Turn, synthesis, gain, and hands-free orchestration. Providers, time, and effects are injected.
src/providers/ Inference requests, authentication, model discovery, and provider errors. The only source directory that directly owns model network access.
src/store/ IndexedDB sessions and preferences, backup persistence/import integration, and the encrypted keyring. Browser storage stays behind small adapters.
src/voice/ Recording, silence detection, speech recognition, transcription, and speech. Browser capability is proved by behaviour, not presence alone.
src/ui/ The application shell, panels, navigation, and browser coordination. The only layer that directly owns the DOM.

There is no package installation or compilation phase. Browser modules are served as written. tools/assemble-site.mjs only copies the publishable tree for browser checks, Pages, and packaging; it does not bundle or rewrite it.

The purity gate

tools/lint-purity.mjs scans src/core/ and src/runtime/ for platform globals such as window, document, browser storage, navigator, and fetch. It runs first in npm test.

Do not weaken the lint to admit a platform API. Move the browser work to its owning layer or inject the dependency. That seam is what keeps prompts deterministic, interrupted turns resumable, and tests fast.

Use the smallest test that can disprove the change

npm test
npm run test:graph
npm run test:browser:required
npm run test:all
Check What it proves When to run it
npm test The purity boundary and the Node unit suite. Continuously while changing pure or injected behaviour.
npm run test:graph Syntax, imports, and the shipped module graph. After moving, adding, or rewiring modules.
npm run test:browser:required IndexedDB, WebCrypto, media, speech, service workers, CSP, the guide, and the assembled site in headless Chrome. For any browser-owned surface. Missing Chrome is a failure.
npm run test:all The complete local gate: unit, graph, and required browser checks. Before pushing a branch.

Tests use Node's built-in runner, injected clocks and fetch functions, and browser probes under test/browser/. A real local-model run is a separate, deliberate check through npm run validate:local; it is not a replacement for the deterministic suite.

Extend through the existing seams

Add a provider Prefer an OpenAI-compatible preset. Use a dedicated adapter only for a different protocol, keep authentication data-driven, update the exact CSP origin, and add new source files to the service-worker shell.
Add a dimension Start with DIMENSIONS. Coverage initialization, selection, prompts, synthesis, and export derive from it; then inspect the few documented labels and engine branches that do not.
Add a UI panel Define the section in index.html, keep active-session ownership in src/ui/app.js, and place panel-specific DOM work in its own UI module.
Add voice behaviour Keep matching and state transitions pure, put browser media in src/voice/, and prove event ordering and no-tap recovery with the browser fixtures.

The focused repository skills add-provider and change-voice-and-driving carry the subsystem-specific checks. A new file under src/ must also appear in sw.js; the wiring tests enforce that cold offline path.

Contribute a focused change

git clone https://github.com/jaypetez/ideaforge.git
cd ideaforge
npm test
npm run serve

Node 22 or newer is enough. There is no npm install. Serve the repository over HTTP because ES modules, IndexedDB, and the service worker do not work from file://.

  1. Read the relevant architecture and invariant sections, then make the smallest coherent change without introducing a dependency or build step.
  2. Add a test that would have caught the failure. Use a browser probe when Node cannot observe the affected API or user flow.
  3. Run focused checks while editing, then npm run test:all before pushing.
  4. Open a pull request against main, state what was verified, and add the release-note label that describes the change. Leave merging to the reviewer unless you were explicitly asked to merge.

The complete contributor policy, provider checklist, assistant setup, and release boundary live in CONTRIBUTING.md.

Continuous integration

The CI workflow runs npm test and the module graph on Linux, Windows, and macOS with Node 22 and 24. A separate Ubuntu job runs the required browser suite. Branch protection requires one stable aggregator named ci; it fails unless every matrix and browser job succeeds, including cancelled or skipped jobs.

The workflow is read-only and has no install or package-cache step. Do not bypass the aggregator or add path filters that can leave a required check waiting forever.

GitHub Pages publishes the tested tree

  1. A successful CI run must come from a push to main.
  2. The Pages workflow verifies the matching ci job and confirms that its tested commit is still the exact tip of main.
  3. tools/assemble-site.mjs copies the application, guide, and generated screenshots into dist/.
  4. The workflow checks the tip again immediately before deploying, so an older run cannot overwrite a newer main branch.

The guide is part of that assembled tree but is deliberately excluded from the app service worker. A failed documentation navigation must never fall back to the application shell.

Releases are tag-driven and separate from Pages

Release work uses the explicitly invoked release skill. Preparation opens a version PR; it is not permission to merge or publish. An authorised maintainer publishes by pushing a vMAJOR.MINOR.PATCH tag at the approved, green commit on main.

The release workflow first checks that the tag, package.json, and src/version.js agree, proves the commit belongs to main, and reruns npm run test:all. Only then may write-enabled jobs publish the reproducible source archives, SHA256SUMS, and the multi-architecture container image. Pages deployment remains an independent main-branch pipeline.

Coding-assistant discovery

Open the repository root so each client can discover the shared instructions and skills. AGENTS.md owns the working loop, CLAUDE.md owns the implementation invariants, and .claude/skills/ contains the one shared definition of each project skill.

Client Entry point Documentation review adapter
Claude Code CLAUDE.md, which imports AGENTS.md ideaforge-docs-review-claude
GitHub Copilot CLI and VS Code .github/copilot-instructions.md plus the shared references ideaforge-docs-review-copilot

Use update-documentation when documentation should be changed and review-ideaforge-documentation for an exact, read-only drift review. Their client adapters expose only read tools and stop when the requested diff is not available.

copilot instruction list --json
copilot skill list --json

In Copilot CLI, /env, /instructions, /skills, and /agent show the loaded configuration. In Claude Code, use /memory and /skills. In VS Code, use the Chat customization and diagnostics views. Start a fresh session after changing instructions, skills, or agents, and do not bypass workspace trust or normal tool approval to make discovery work.