molecule-core/CONTRIBUTING.md
claude-ceo-assistant 3501e6bfd7
Some checks failed
CodeQL / Analyze (${{ matrix.language }}) (go) (pull_request) Successful in 13s
CodeQL / Analyze (${{ matrix.language }}) (python) (pull_request) Successful in 11s
CodeQL / Analyze (${{ matrix.language }}) (javascript-typescript) (pull_request) Successful in 12s
Check merge_group trigger on required workflows / Required workflows have merge_group trigger (pull_request) Successful in 15s
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 27s
CI / Detect changes (pull_request) Successful in 20s
Retarget main PRs to staging / Retarget to staging (pull_request) Has been skipped
Lint curl status-code capture / Scan workflows for curl status-capture pollution (pull_request) Successful in 15s
E2E API Smoke Test / detect-changes (pull_request) Successful in 51s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 51s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 39s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 51s
Harness Replays / detect-changes (pull_request) Successful in 53s
Runtime PR-Built Compatibility / detect-changes (pull_request) Successful in 48s
Ops Scripts Tests / Ops scripts (unittest) (pull_request) Successful in 1m7s
CI / Shellcheck (E2E scripts) (pull_request) Successful in 31s
Harness Replays / Harness Replays (pull_request) Failing after 1m18s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 2m19s
Runtime PR-Built Compatibility / PR-built wheel + import smoke (pull_request) Successful in 3m14s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 6m1s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 6m47s
CI / Python Lint & Test (pull_request) Successful in 8m16s
CI / Canvas (Next.js) (pull_request) Failing after 9m36s
CI / Canvas Deploy Reminder (pull_request) Has been skipped
CI / Platform (Go) (pull_request) Successful in 12m18s
fix(post-suspension): vanity import paths go.moleculesai.app/core/{platform,tests/harness/cp-stub} (closes molecule-ai/internal#71 phase 2)
Migrates the two Go modules under molecule-core off the dead
github.com/Molecule-AI/molecule-monorepo/... identity onto the vanity
host go.moleculesai.app. Also fixes the historical naming
inconsistency where the Gitea repo is molecule-core but the Go module
path said molecule-monorepo.

Module changes:
- workspace-server/go.mod:
    github.com/Molecule-AI/molecule-monorepo/platform
    -> go.moleculesai.app/core/platform
- tests/harness/cp-stub/go.mod:
    github.com/Molecule-AI/molecule-monorepo/tests/harness/cp-stub
    -> go.moleculesai.app/core/tests/harness/cp-stub

Surfaces touched
- 174 *.go files (374 import lines) — every import under
  workspace-server/ + tests/harness/cp-stub/
- 2 Dockerfiles (workspace-server/Dockerfile + Dockerfile.tenant) —
  -ldflags strings updated in lockstep with the module rename so
  buildinfo.GitSHA injection still resolves correctly
- README + docs + scripts + comment URLs to git.moleculesai.app form
- NEW workspace-server/internal/lint/import_path_lint_test.go —
  structural lint gate rejecting future github.com/Molecule-AI/ or
  Molecule-AI/molecule-monorepo references. Identical template to the
  other migration PRs (plugin-gh-identity#3, molecule-cli#2,
  molecule-controlplane#32).

Cross-repo dep allowlist (documented in lint gate)
workspace-server requires molecule-ai-plugin-gh-identity, whose own
vanity migration is PR molecule-ai-plugin-gh-identity#3. Until that PR
merges + a tag is cut at go.moleculesai.app/plugin/gh-identity, the
two locations referencing the legacy github.com path
(workspace-server/go.mod require, cmd/server/main.go import) remain
allowlisted. Follow-up PR drops the allowlist + updates both refs in
one shot once gh-identity is fully migrated.

Test plan
- go build ./... clean for both modules
- go test ./... green except two pre-existing failures
  (TestStartSweeper_RecordsMetricsOnSuccess flaky-on-suite,
  TestLocalResolver_BubblesUpCopyFailure relies on read-only fs perms
  but runs as root on operator host) — both reproduce identically on
  baseline main pre-migration; NOT regressions of this PR
- Mutation-tested: lint gate fails on canaries in .go + .md;
  allowlist correctly suppresses cross-repo dep references in go.mod
  while still flagging unrelated additions

Open dependency
- go.moleculesai.app responder must be deployed before fresh-clone
  external builds resolve the vanity path. Existing CI / Docker builds
  ride pinned go.sum + self-referential module path + responder is
  not on critical path for those.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 22:37:42 +00:00

8.4 KiB

Contributing to Molecule AI

Thanks for your interest in contributing to Molecule AI! This guide covers the development workflow, conventions, and how to get your changes merged.

Getting Started

Prerequisites

  • Go 1.25+ — platform backend
  • Node.js 20+ — canvas frontend
  • Python 3.11+ — workspace runtime
  • Docker — infrastructure services (Postgres, Redis)
  • Git — with hooks path set to .githooks
  • jq — parses manifest.json during setup.sh to clone the template/plugin registry. Install via brew install jq (macOS) or apt install jq (Debian). Without it, setup.sh prints a note and leaves the registry dirs empty (recoverable by installing jq and re-running).

Setup

# Clone the repo
git clone https://git.moleculesai.app/molecule-ai/molecule-core.git
cd molecule-core

# Install git hooks
git config core.hooksPath .githooks

# Copy and edit .env (generate ADMIN_TOKEN + SECRETS_ENCRYPTION_KEY)
cp .env.example .env

# Start infrastructure (Postgres, Redis, Langfuse, Temporal)
./infra/scripts/setup.sh

# Build and run the platform — applies pending migrations on first boot
cd workspace-server
go run ./cmd/server

# In a separate terminal, run the canvas
cd canvas
npm install
npm run dev

Environment Variables

Copy .env.example to .env and fill in your values:

cp .env.example .env

See CLAUDE.md for a full list of environment variables and their purposes.

What goes where (content vs code)

This repo is scoped to code (canvas, workspace, workspace-server, related infra). Public content (blog posts, marketing copy, OG images, SEO briefs, DevRel demos) lives in Molecule-AI/docs. The Block forbidden paths CI gate fails any PR that writes to marketing/ or other removed paths — open against Molecule-AI/docs instead.

Content type Target
Blog posts Molecule-AI/docscontent/blog/<YYYY-MM-DD-slug>/
Doc pages Molecule-AI/docscontent/docs/
Marketing copy / PMM positioning Molecule-AI/docsmarketing/
OG images, visual assets Molecule-AI/docsapp/ or marketing/
SEO briefs Molecule-AI/docsmarketing/
DevRel demos (runnable code) Standalone repo under Molecule-AI/, OR embedded in Molecule-AI/docs
Launch checklists, internal tracking GitHub Issues — not committed files
Engineering docs (docs/adr/, docs/architecture/, docs/incidents/) This repo (internal, not published)
Live product pages (e.g. canvas/src/app/pricing/page.tsx) This repo (these are app code, not marketing copy)

If a PR fails the Block forbidden paths check, the contents belong in Molecule-AI/docs. No CI drag, no Canvas E2E, content lands in minutes.

Development Workflow

Branch Naming

Use prefixed branches:

  • feat/ — new features
  • fix/ — bug fixes
  • chore/ — maintenance, deps, CI
  • docs/ — documentation only

Never push directly to main. All changes go through pull requests.

Commits

Write concise commit messages that focus on the "why":

fix(canvas): prevent infinite re-render on WebSocket reconnect

The useEffect dependency array included the entire nodes object,
causing a render loop when any node position changed.

Pull Requests

  • Keep PRs focused — one concern per PR
  • Include a test plan in the PR description
  • PRs are merged with merge commits (not squash or rebase)

Auto-merge & the "extra commit" trap

Two system guards protect against pushing commits after auto-merge has been enabled. Don't try to work around them — they exist because we shipped a half-merged PR on 2026-04-27 (#2174 merged with only its first commit; the second was orphaned on a branch GitHub had already deleted).

  1. Repo-wide: "Automatically delete head branches" is on. Once a PR merges, the branch is deleted server-side. Any subsequent git push to that branch fails with remote rejected — no such branch.

  2. CI: the pr-guards workflow (calling molecule-ci disable-auto-merge-on-push) fires on every push to an open PR. If auto-merge was already enabled, it's disabled and a comment is posted. You must explicitly re-enable after verifying the new commit.

Workflow rules that follow from the guards:

  • Push all commits before running gh pr merge --auto.
  • If you realize you need another commit after enabling auto-merge: push it, then re-run gh pr merge --auto — the guard will already have disabled it. The disable + re-enable is the verification step.
  • For changes that depend on each other across PRs (e.g. a build-script change + a workflow that consumes it), prefer a stack of PRs (PR-B branched off PR-A's branch, opened only after PR-A is in queue) over amending one in-flight PR.

Running Tests

# Go (platform)
cd workspace-server && go test -race ./...

# Canvas (Next.js)
cd canvas && npm test

# Workspace runtime (Python)
cd workspace && python -m pytest -v

# E2E API tests (requires running platform)
bash tests/e2e/test_api.sh

Pre-commit Hooks

The .githooks/pre-commit hook enforces:

  • 'use client' directive on React hook files
  • Dark theme only (no white/light CSS classes)
  • No SQL injection patterns (fmt.Sprintf with SQL)
  • No leaked secrets (sk-ant-, ghp_, AKIA)

Fix violations before committing — the hook will reject the commit.

CI Pipeline

CI runs on GitHub Actions with a self-hosted runner. External contributors: PRs from forks will not trigger CI automatically. A maintainer will review and run CI manually.

Job What it checks
platform-build Go build + vet + go test -race
canvas-build npm build + vitest
python-lint pytest with coverage
e2e-api Full API test suite (62 tests)
shellcheck Shell script linting

Code Style

Go (Platform)

  • Standard gofmt formatting
  • go vet must pass
  • No fmt.Sprintf in SQL queries (use parameterized queries)
  • Prefer function injection over import cycles

TypeScript (Canvas)

  • Strict mode enabled
  • No any types (use unknown or proper types)
  • Use ConfirmDialog component, never native confirm/alert/prompt
  • Dark theme only — no white/light CSS classes

Python (Workspace Runtime)

  • Type hints on public functions
  • pytest for all tests

External integrations

Code in this repo lands in molecule-core. Some related runtime artifacts live in their own repos:

  • Molecule-AI/molecule-ai-workspace-runtime — Python adapter SDK (molecule_runtime) that runs inside containerized Molecule workspaces. Bridges Claude Code SDK / hermes / langgraph / etc. → A2A queue.
  • Molecule-AI/molecule-sdk-pythonA2AServer + RemoteAgentClient for external agents that register over the public /registry/register flow.
  • Molecule-AI/molecule-mcp-claude-channel — Claude Code channel plugin. Bridges A2A traffic into a running Claude Code session via MCP notifications/claude/channel. Polling-based (no tunnel required); install with claude --channels plugin:molecule@Molecule-AI/molecule-mcp-claude-channel.

When extending the A2A surface in molecule-core (workspace-server/internal/handlers/a2a_proxy.go etc.), consider whether the change has a downstream impact on the runtime SDK or the channel plugin — they're versioned independently but share the wire shape.

Architecture Overview

See CLAUDE.md for detailed architecture documentation, including:

  • Component diagram (Platform, Canvas, Workspace Runtime)
  • Key architectural patterns
  • Database schema and migrations
  • API route reference

Reporting Issues

Use GitHub Issues with a clear title and reproduction steps. Include:

  • What you expected
  • What actually happened
  • Platform/OS version
  • Relevant logs or screenshots

Security

If you discover a security vulnerability, please report it privately via GitHub Security Advisories rather than opening a public issue.

License

By contributing, you agree that your contributions will be licensed under the same Business Source License 1.1 that covers this project.