import from local vendored copy (2026-05-06)
Some checks failed
CI / validate (push) Failing after 0s

This commit is contained in:
Hongming Wang 2026-05-06 13:53:26 -07:00
commit af4e0faeef
13 changed files with 622 additions and 0 deletions

5
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,5 @@
name: CI
on: [push, pull_request]
jobs:
validate:
uses: Molecule-AI/molecule-ci/.github/workflows/validate-plugin.yml@main

21
.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
# Credentials — never commit. Use .env.example as the template.
.env
.env.local
.env.*.local
.env.*
!.env.example
!.env.sample
# Private keys + certs
*.pem
*.key
*.crt
*.p12
*.pfx
# Secret directories
.secrets/
# Workspace auth tokens
.auth-token
.auth_token

View File

@ -0,0 +1 @@
pyyaml>=6.0

View File

@ -0,0 +1,52 @@
#!/usr/bin/env python3
"""Validate a Molecule AI plugin repo."""
import os, sys, yaml
errors = []
# 1. plugin.yaml exists
if not os.path.isfile("plugin.yaml"):
print("::error::plugin.yaml not found at repo root")
sys.exit(1)
with open("plugin.yaml") as f:
plugin = yaml.safe_load(f)
# 2. Required fields
for field in ["name", "version", "description"]:
if not plugin.get(field):
errors.append(f"Missing required field: {field}")
# 3. Version format
v = str(plugin.get("version", ""))
if v and not all(c in "0123456789." for c in v):
errors.append(f"Invalid version format: {v}")
# 4. Runtimes type
runtimes = plugin.get("runtimes")
if runtimes is not None and not isinstance(runtimes, list):
errors.append(f"runtimes must be a list, got {type(runtimes).__name__}")
# 5. Has content
content_paths = ["SKILL.md", "hooks", "skills", "rules"]
found = [p for p in content_paths if os.path.exists(p)]
if not found:
errors.append("Plugin must contain at least one of: SKILL.md, hooks/, skills/, rules/")
# 6. SKILL.md formatting check
if os.path.isfile("SKILL.md"):
with open("SKILL.md") as f:
first_line = f.readline().strip()
if first_line and not first_line.startswith("#"):
print("::warning::SKILL.md should start with a markdown heading (e.g., # Plugin Name)")
if errors:
for e in errors:
print(f"::error::{e}")
sys.exit(1)
print(f"✓ plugin.yaml valid: {plugin['name']} v{plugin['version']}")
if found:
print(f" Content: {', '.join(found)}")
if runtimes:
print(f" Runtimes: {', '.join(runtimes)}")

155
CLAUDE.md Normal file
View File

@ -0,0 +1,155 @@
# molecule-dev — Molecule AI Codebase Conventions Plugin
`molecule-dev` is a **platform conventions plugin** that captures hard-won lessons from Molecule AI's production codebase. Rather than repeating mistakes, every agent working on the platform benefits from rules derived from real bugs and production failures.
**Version:** 1.0.0
**Runtime:** `claude_code`, `deepagents`, `hermes`
---
## Repository Layout
```
molecule-dev/
├── plugin.yaml — Plugin manifest (runtimes, rules, skills)
├── rules/
│ └── codebase-conventions.md — Platform-wide conventions (Canvas/Go/Python)
├── skills/
│ └── review-loop/SKILL.md — Multi-round review orchestration workflow
└── adapters/ — Harness adaptors (thin wrappers)
```
---
## Conventions Summary
See `rules/codebase-conventions.md` for the full ruleset. Key highlights:
### Canvas (Next.js 15 App Router)
- **`'use client'` is non-negotiable** — every `.tsx` file using React hooks or event handlers must declare it as the very first line.
- **Zustand selectors**: never call a function returning a new object inside a selector — use `useMemo` instead.
- **Dark zinc theme** — backgrounds `zinc-900`/`zinc-950`, text `zinc-300`/`zinc-400`. Never use `#ffffff` or light colors.
- **Verify API response shapes** with `curl` or Go handler inspection — don't assume.
### Platform (Go)
- **SQL safety**: always parameterized queries (`$1`, `$2`), always `ExecContext`/`QueryContext`.
- **Access control**: every workspace endpoint must verify ownership; new A2A proxy paths must pass `CanCommunicate()`.
- **Container lifecycle**: use `ContainerRemove(Force: true)` — never `ContainerStop` + `ContainerRemove` separately.
### Workspace Runtime (Python)
- **Error sanitization**: use `sanitize_agent_error()` — never emit raw exception messages or subprocess stderr to the user.
- **System prompt hot-reload**: always use `encoding="utf-8", errors="replace"` when reading prompt files.
---
## Development
### Prerequisites
- Node.js >= 18 (for markdownlint)
- Python 3.11+ (for `adapters/`)
- `gh` CLI authenticated
- Write access to `Molecule-AI/molecule-ai-plugin-molecule-dev`
### Setup
```bash
git clone https://github.com/Molecule-AI/molecule-ai-plugin-molecule-dev.git
cd molecule-ai-plugin-molecule-dev
# Install markdownlint CLI for pre-commit linting
npm install -g markdownlint-cli
# Validate the plugin structure
gh workflow run validate-plugin.yml --ref main
```
### Adapter Dev
```bash
python3 -m venv .venv && source .venv/bin/activate
pip install plugins_registry
python -c "from adapters.claude_code import Adaptor; print('OK')"
```
### Pre-Commit Checklist
```bash
# Markdown lint
npx markdownlint '**/*.md' --ignore node_modules
# YAML validation
python3 -c "import yaml; yaml.safe_load(open('plugin.yaml'))"
# No pycache committed
find . -name '__pycache__' -o -name '*.pyc' | grep -v .gitignore && exit 1
```
---
## Test Commands
There are no unit tests in this plugin — it is a configuration-only package. Validation is done by the shared `validate-plugin.yml` workflow (see CI).
To run validation locally:
```bash
gh workflow run validate-plugin.yml --ref main
```
To validate `plugin.yaml` structure:
```bash
python3 -c "
import yaml, os
with open('plugin.yaml') as f:
data = yaml.safe_load(f)
for key in ['rules', 'skills']:
for ref in data.get(key, []):
path = ref if ref.endswith('.md') else ref + '.md'
print(f'[OK] {path}' if os.path.exists(path) else f'[MISSING] {path}')
"
```
---
## Release Process
1. **Review changes**`git log origin/main..HEAD --oneline`
2. **Validate** — run `npx markdownlint` on all `.md` files
3. **Bump version** in `plugin.yaml`
4. **Commit**`chore: bump version to X.Y.Z`
5. **Tag**`git tag -a vX.Y.Z -m "Release vX.Y.Z"` and push
6. **Create GitHub Release** with a changelog section
7. **Verify CI green** on the release commit
---
## Key Contacts
| Role | Owner |
|------|-------|
| Platform architecture (Go/Canvas) | Molecule AI Engineering |
| Workspace runtime (Python) | Molecule AI Engineering |
| Plugin maintenance | Molecule AI Engineering |
For questions, bugs, or suggestions, open an issue in this repo or reach out via the Molecule AI internal channels.
---
## Adding a New Convention
1. Create `rules/<rule-name>.md` describing the convention.
2. Add it to `rules:` in `plugin.yaml` (and add `rules/` section if not present).
3. If it affects canvas work, include a concrete code example (BAD / GOOD pattern).
4. Run markdownlint validation before committing.
---
## Adding a New Skill
1. Create `skills/<skill-name>/SKILL.md` with YAML frontmatter (`name`, `description`).
2. Add it to `skills:` in `plugin.yaml`.
3. Skills are the canonical workflow surface — prefer skills over commands.

19
README.md Normal file
View File

@ -0,0 +1,19 @@
# molecule-dev
Molecule AI plugin. Install via the Molecule AI platform plugin system.
## Usage
### In org template (org.yaml)
```yaml
plugins:
- molecule-dev
```
### From URL (community install)
```
github://Molecule-AI/molecule-ai-plugin-molecule-dev
```
## License
Business Source License 1.1 — © Molecule AI.

2
adapters/claude_code.py Normal file
View File

@ -0,0 +1,2 @@
"""Claude Code adaptor — uses the generic rule+skill installer."""
from plugins_registry.builtins import AgentskillsAdaptor as Adaptor # noqa: F401

2
adapters/deepagents.py Normal file
View File

@ -0,0 +1,2 @@
"""DeepAgents adaptor — uses the generic rule+skill installer."""
from plugins_registry.builtins import AgentskillsAdaptor as Adaptor # noqa: F401

97
known-issues.md Normal file
View File

@ -0,0 +1,97 @@
# Known Issues
Active and recently resolved issues for `molecule-dev`.
---
## Active Issues
*(None currently open. This section is updated when issues are filed.)*
---
## Recently Resolved
### [RESOLVED] plugin.yaml Merge Conflict Residue
**Severity:** P2
**Resolved in:** v1.0.0
**Symptoms:** `plugin.yaml` contained residual merge conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) that caused YAML parsing to fail. The `runtimes:` section listed `claude_code`, `deepagents` in the main branch while the working copy attempted to add `hermes`.
**Cause:** A `git stash` operation was used to temporarily discard local changes; on `git stash pop`, the conflicted state was re-applied and committed without conflict resolution.
**Fix:** Resolved by overwriting `plugin.yaml` with clean, conflict-free content. The file now has 3 runtimes declared and the `rules:` section populated.
**Prevention:** Never `git add` a file containing conflict markers. Use `git add <file>` only after `<<<<<<<` markers are fully removed, or use `git mergetool`.
---
## Known Gotchas
These are not bugs but behaviors that may surprise contributors:
### `rules/` section missing from plugin.yaml
**Symptoms:** Adding a new rule file and referencing it in `plugin.yaml` may silently fail if the `rules:` key is absent.
**Workaround:** Verify `plugin.yaml` contains the top-level `rules:` key before adding rule references. If absent, add it:
```yaml
rules:
- rules/codebase-conventions.md
- rules/<new-rule>.md
```
### `hermes` runtime requires adapter
**Symptoms:** Installing the plugin for a `hermes` workspace runtime works, but at runtime the adapter import may fail if `plugins_registry` is not installed in the harness environment.
**Workaround:** This is expected in isolated dev environments. The harness handles adapter resolution at runtime. See `runbooks/local-dev-setup.md` in the repo for local adapter testing.
### No local test runner
**Symptoms:** `npm test` / `python -m pytest` return no results — there are no unit tests in this plugin.
**Workaround:** This is by design — the plugin is a configuration package. Validation is done by the shared `validate-plugin.yml` workflow in CI. Run it locally via `gh workflow run validate-plugin.yml --ref main`.
---
## How to Update This File
When a new issue is discovered:
1. Add it under **Active Issues** using the template below.
2. Include: symptom, cause (if known), workaround, and fix (if resolved).
3. When fixed, move it to **Recently Resolved** and note the fix version.
### Issue Template
```markdown
## [TICKET-NUMBER] <Short Title>
**Severity:** P0 / P1 / P2 / P3
**Status:** Workaround / Fix in progress / Fix available / Resolved in vX.Y.Z
**Symptoms:**
**Cause:**
**Workaround:**
**Fix (if available):**
```
---
## Severity Definitions
| Level | Description |
|-------|-------------|
| P0 | Plugin fails to load entirely; no workaround |
| P1 | Core convention violated; can cause production failures |
| P2 | Non-core issue; minor impact or workaround available |
| P3 | Cosmetic; edge case; informational |
---
## Reporting
Use the Molecule-AI/internal issue tracker. Tag issues with `plugin-molecule-dev`.

16
plugin.yaml Normal file
View File

@ -0,0 +1,16 @@
name: molecule-dev
version: 1.0.0
description: Molecule AI codebase conventions, past bugs, quality standards, and coordination workflows
author: Molecule AI
tags: [conventions, quality, coordination, codebase]
runtimes:
- claude_code
- deepagents
- hermes
rules:
- rules/codebase-conventions.md
skills:
- review-loop

View File

@ -0,0 +1,101 @@
# Molecule AI Codebase Conventions
These rules apply to every agent working on the Molecule AI / Molecule AI codebase.
They are lessons learned from real bugs — not style preferences. Violating them
causes production failures.
## Canvas (Next.js 15 App Router)
### `'use client'` — NON-NEGOTIABLE
Every `.tsx` file in `canvas/src/` that uses React hooks (`useState`, `useEffect`,
`useCallback`, `useMemo`, `useRef`), Zustand stores (`useCanvasStore`, `useSecretsStore`),
or event handlers (`onClick`, `onChange`) MUST have `'use client';` as the very first
line. Without it, Next.js renders the component as server HTML and React never hydrates
it — buttons appear but silently don't respond to clicks.
**This has caused two reverted PRs.** Always run this check before reporting done:
```bash
cd canvas
for f in $(grep -rl "useState\|useEffect\|useCallback\|useMemo\|useRef\|useStore\|onClick\|onChange" src/ --include="*.tsx"); do
head -3 "$f" | grep -q "use client" || echo "MISSING 'use client': $f"
done
```
### Zustand Selectors — No New Objects
Never call a function that returns a new object inside a Zustand selector:
```typescript
// BAD — creates new object every render → infinite re-renders
const grouped = useSecretsStore((s) => s.getGrouped());
// GOOD — use useMemo with stable selector values
const secrets = useSecretsStore((s) => s.secrets);
const grouped = useMemo(() => groupSecrets(secrets), [secrets]);
```
### Dark Zinc Theme — No Light Colors
The canvas is dark-themed. Every new component must use:
- Backgrounds: `zinc-900`, `zinc-950`, `#18181b`, `#09090b`
- Text: `zinc-300`, `zinc-400`, `#d4d4d8`, `#a1a1aa`
- Accents: `blue-500`, `blue-600`, `violet-500`
- Borders: `zinc-700`, `zinc-800`
- Never: `white`, `#ffffff`, `#f5f5f5`, or any light gray
### API Response Shapes
Always verify the actual platform API response format before writing fetch code.
Check the Go handler or test with curl — don't assume. Past bug: FE assumed
`GET /settings/secrets` returned a flat array but it returns `{ secrets: [...] }`.
## Platform (Go)
### SQL Safety
- Always use parameterized queries (`$1`, `$2`), never string concatenation
- Use `ExecContext` / `QueryContext` with context, never bare `Exec` / `Query`
- Always check `rows.Err()` after iterating result sets
- JSONB: convert `[]byte` to `string()` and use `::jsonb` cast
### Access Control
- Every endpoint touching workspace data must verify ownership
- A2A proxy calls go through `CanCommunicate()` — new proxy paths must respect it
- System callers (`webhook:*`, `system:*`, `test:*`) bypass via `isSystemCaller()`
### Container Lifecycle
- Use `ContainerRemove(Force: true)` to stop containers — never `ContainerStop` +
`ContainerRemove` separately (restart policy race condition causes zombies)
- Always reap zombie processes: `proc.wait()` after `proc.kill()` with a timeout
## Workspace Runtime (Python)
### Error Sanitization
Never emit raw exception messages or subprocess stderr to the user. Use
`sanitize_agent_error()` which exposes the exception class name but strips
the message body (which can leak tokens, paths, and stack traces).
### System Prompt Hot-Reload
System prompts are re-read from `/configs/system-prompt.md` on every message.
Always use `encoding="utf-8", errors="replace"` when reading prompt files.
## Inter-Agent Communication
### Parallel Delegation
Use `delegate_task_async` to send tasks to multiple peers simultaneously.
Don't serialize what can be parallel — fire all async delegations, then poll
`check_task_status` to collect results as they finish.
### Side Questions
Any agent can ask a peer a direct question via `delegate_task` (sync) without
going through the lead. FE can ask BE "what's the API response format?" mid-task.
Use this to avoid guessing — it's faster than getting it wrong.
### Proactive Updates
Use `send_message_to_user` to push status updates to the CEO's chat at any time.
Don't wait until everything is done to report — acknowledge immediately, update
during long work, deliver results when complete.
## Before Reporting Done
Every agent, regardless of role, must verify their own work before claiming completion:
1. Read back every file you changed — confirm it looks right
2. Run the relevant test suite (`npm test`, `go test`, `python -m pytest`)
3. Run the relevant build (`npm run build`, `go build`)
4. Check for framework-specific gotchas (the `'use client'` grep above)
5. If you can imagine a way your change could break, test that scenario

View File

@ -0,0 +1,73 @@
# Local Development Setup
This runbook covers setting up a local development environment for
`molecule-dev`.
---
## Prerequisites
- Python 3.11+
- `gh` CLI authenticated
- Write access to `Molecule-AI/molecule-ai-plugin-molecule-dev`
---
## Clone & Bootstrap
```bash
git clone https://github.com/Molecule-AI/molecule-ai-plugin-molecule-dev.git
cd molecule-ai-plugin-molecule-dev
```
---
## Validating Plugin Structure
```bash
python3 -c "import yaml; yaml.safe_load(open('plugin.yaml'))"
echo "plugin.yaml OK"
```
---
## Testing the Dev Tools
Run the test suite to verify all dev tooling is functional:
```bash
python3 -m pytest tests/ -v
```
---
## Writing New Rules or Skills
1. Create `rules/<rule-name>/RULES.md` or `skills/<skill-name>/SKILL.md`
2. Follow the format of existing rules/skills in the repo
3. Validate the plugin structure (above)
4. Add tests in `tests/` if applicable
---
## Troubleshooting
### "No module named yaml"
Install PyYAML:
```bash
pip install pyyaml
```
### Plugin validation fails
- Ensure `plugin.yaml` has all required fields: `name`, `version`, `description`
- Ensure at least one of: `SKILL.md`, `hooks/`, `skills/`, `rules/`
- Check the schema with: `python3 -c "import yaml; yaml.safe_load(open('plugin.yaml'))"`
---
## Related
- `skills/molecule-dev/SKILL.md` — dev tooling documentation
- `rules/` — existing rules

View File

@ -0,0 +1,78 @@
---
name: review-loop
description: "Orchestrate a multi-round implementation + review cycle. Use when coordinating a feature that requires implementation (FE/BE), design review (UIUX), security review, and QA verification. Ensures QA findings get routed back for fixes until clean."
---
# Review Loop
Orchestrate implementation through multiple rounds until QA reports zero issues.
This prevents the one-shot delegation problem where QA finds bugs but nobody
fixes them.
## When to Use
Use this when you're a coordinator (Dev Lead, PM) assigning a feature that
involves multiple specialists.
## The Loop
### Round 1: Design + Implementation (parallel where possible)
1. **Identify all stakeholders** — before delegating, ask: who needs to be involved?
- UI work → UIUX Designer reviews interaction design FIRST
- Credentials / auth / secrets → Security Auditor reviews
- API changes → Backend Engineer + Frontend Engineer coordinate
- Everything → QA Engineer is the final gate
2. **Delegate design review first** (if UI work):
```
delegate_task_async → UIUX Designer: "Review the interaction design for [feature]"
```
3. **Delegate implementation** (after design, or parallel if non-UI):
```
delegate_task_async → Frontend Engineer: "Implement [feature] following UIUX spec"
delegate_task_async → Backend Engineer: "Add [endpoint]" (if needed)
delegate_task_async → Security Auditor: "Review [feature] for [specific concerns]"
```
4. **Delegate QA** (can start in parallel — QA reads existing code while FE works):
```
delegate_task_async → QA Engineer: "Review [feature], run full test suite, write missing tests, grep for convention violations"
```
5. **Collect all results** via `check_task_status` on each delegation.
### Round 2: Fix QA Findings (if any issues found)
If QA reported issues:
1. **Send QA's findings back to the implementer:**
```
delegate_task → Frontend Engineer: "QA found these issues in your implementation:
[paste QA's specific findings with file:line references]
Fix all of them and report back."
```
2. **Re-run QA on the fixes:**
```
delegate_task → QA Engineer: "FE applied fixes for your findings. Re-verify:
[paste the specific issues that were fixed]
Run the test suite again. Report if any issues remain."
```
3. **If QA still finds issues → repeat Round 2.**
### Round 3: Final Sign-off
When QA reports zero issues:
- Compile the full report: what was implemented, what was fixed, test results
- Report to PM / CEO with substance, not just "done"
## Key Rules
- **Never skip QA.** Even if FE says "I tested it." QA verifies independently.
- **Never skip Security for credential-related features.** A secrets panel without security review is a liability.
- **QA findings are not optional.** If QA found it, it gets fixed. Period.
- **Use parallel delegation.** `delegate_task_async` to all specialists at once, then collect with `check_task_status`. Don't serialize what can be concurrent.
- **Ask side questions.** If FE needs to know the API shape, FE should `delegate_task` directly to BE — don't relay through the lead.