docs: add CLAUDE.md, known-issues.md, and runbooks/local-dev-setup.md

Sync docs from master to main (default branch).
This commit is contained in:
Molecule AI · plugin-dev 2026-04-21 10:54:40 +00:00
parent 11afacbbdc
commit 85dfd699d1
3 changed files with 605 additions and 0 deletions

219
CLAUDE.md Normal file
View File

@ -0,0 +1,219 @@
# Molecule AI Workspace Template — langgraph
## Purpose
This is a **workspace template** for the langgraph runtime. It provides a pre-configured
workspace environment (Dockerfile, config.yaml, adapter.py, system-prompt.md, and
supporting files) that Molecule AI agents run inside. It is NOT a plugin — it has no
`plugin.yaml` and no `rules/` directory.
Use this template when you want to bootstrap a langgraph-based agentic workflow within
the Molecule platform.
---
## Key Files and Their Roles
| File | Role |
|---|---|
| `config.yaml` | Runtime configuration: schema version, model, runtime (langgraph), tool registry, skill paths, env-var bindings |
| `adapter.py` | Thin bridge between the Molecule platform and the langgraph runtime. Responsible for initialising the graph, routing messages, streaming results, and forwarding HEARTBEAT events |
| `system-prompt.md` | System-level instructions injected into every agent turn (identity, constraints, output format) |
| `AGENTS.md` | Defines the set of named agents (nodes) in the langgraph graph, their roles, and how they are wired together |
| `BOOTSTRAP.md` | Startup sequence: how the adapter initialises state, loads persisted checkpoints, and validates the graph |
| `HEARTBEAT.md` | Describes the HEARTBEAT protocol — when the adapter emits a heartbeat, what payload it carries, and how the platform consumes it |
| `SOUL.md` | Core philosophy / "identity document" for the workspace — values, reasoning style, tone |
| `TOOLS.md` | Catalog of tools available to agents, including descriptions, parameter schemas, and usage conventions |
| `requirements.txt` | Python dependencies (langgraph SDK, platform client, LLM client, utilities) |
| `Dockerfile` | Container image definition for the runtime environment |
---
## Runtime Configuration Conventions
- All runtime configs live in `config.yaml` at the workspace root.
- The top-level `schema_version` field must match the platform's supported schema range
(e.g. `1.0` `1.2`; see the platform release notes).
- Environment-variable substitution uses `${VAR_NAME}` syntax inside string values.
- Sections: `runtime`, `model`, `tools`, `skills`, `checkpoint`, `observability`.
```yaml
schema_version: "1.1"
runtime:
name: langgraph
version: "0.4" # must match installed langgraph package major.minor
checkpoint:
backend: memory # "memory" for dev, "postgres" for prod
conn: "${CHECKPOINT_DB_URL}"
model:
provider: anthropic
name: claude-sonnet-4-6
max_tokens: 8192
temperature: 0.7
system_prompt_file: system-prompt.md
tools:
registry: builtin
allowed_tools:
- browser_search
- code_interpreter
- file_read
- file_write
- bash
skills:
load_paths:
- /opt/molecule/skills
auto_init: true
observability:
heartbeat_interval_seconds: 30
log_level: INFO
```
---
## Environment Variables Expected
| Variable | Required | Description |
|---|---|---|
| `ANTHROPIC_API_KEY` | Yes | API key for the LLM provider |
| `CHECKPOINT_DB_URL` | No | Postgres connection string for langgraph checkpoint persistence (defaults to in-memory) |
| `MOLECULE_PLATFORM_URL` | Yes | Base URL of the Molecule platform (e.g. `https://platform.molecule.ai`) |
| `MOLECULE_WORKSPACE_ID` | Yes | Workspace instance ID assigned by the platform |
| `LANGGRAPH_CHECKPOINT_NS` | No | Namespace string used to prefix checkpoint keys |
| `LOG_LEVEL` | No | Python log level override (`DEBUG`, `INFO`, `WARNING`) |
---
## Skill Loading
Skills are loaded at startup from paths declared in `config.yaml` under `skills.load_paths`.
The adapter calls `molecule.skills.load(path)` for each path before entering the run loop.
Only skills whose manifest (`skill.yaml`) declares compatibility with `langgraph` runtime
are activated. Skills that declare `runtime: "*"` are always loaded.
Auto-initialisation is controlled by `skills.auto_init: true` (default). Set to `false`
to disable automatic skill loading and manage loading manually in `BOOTSTRAP.md`.
---
## Development Setup
### Prerequisites
- Python 3.11+
- Docker 24+ / Docker Compose v2
- Git
### Clone and install
```bash
git clone https://github.com/your-org/molecule-ai-workspace-template-langgraph.git
cd molecule-ai-workspace-template-langgraph
pip install -r requirements.txt
```
### Run adapter locally (outside Docker)
```bash
export ANTHROPIC_API_KEY="sk-ant-..."
export MOLECULE_PLATFORM_URL="https://platform.molecule.ai"
export MOLECULE_WORKSPACE_ID="ws-dev-local"
python adapter.py
```
The adapter will print the resolved config on startup and begin polling for agent tasks.
### Test the Docker build
```bash
docker build -t molecule-langgraph-workspace:dev .
docker run --rm \
-e ANTHROPIC_API_KEY \
-e MOLECULE_PLATFORM_URL \
-e MOLECULE_WORKSPACE_ID \
molecule-langgraph-workspace:dev
```
### Docker Compose (full local stack)
```yaml
# docker-compose.yml (add to workspace root)
version: "3.9"
services:
workspace:
build: .
env_file: .env.local
volumes:
- ./config.yaml:/workspace/config.yaml:ro
depends_on:
- checkpoint-db
checkpoint-db:
image: postgres:16-alpine
environment:
POSTGRES_DB: langgraph_checkpoint
POSTGRES_USER: langgraph
POSTGRES_PASSWORD: langgraph
ports:
- "5432:5432"
```
Run with:
```bash
docker compose up --build
```
---
## Testing
| Test type | Command | Notes |
|---|---|---|
| Unit (adapter) | `pytest tests/test_adapter.py -v` | Mocks the platform API; tests config parsing, graph init |
| Unit (graph wiring) | `pytest tests/test_graph.py -v` | Verifies agent nodes and edges are correctly wired |
| Integration | `docker compose -f compose.test.yml up --abort-on-container-exit` | Full stack; requires `.env.test` with live API keys |
| Lint | `ruff check .` | Must pass before release |
---
## Release Process
1. **Update `config.yaml` schema version** to match the target platform release:
```yaml
schema_version: "1.2" # bump to match platform
```
2. **Bump runtime version pin** in `requirements.txt`:
```
langgraph>=0.4.0,<0.5.0
```
3. **Run the full test suite** — all tests must pass.
4. **Tag the release**:
```bash
git tag -a v1.2.0 -m "release: align with platform schema 1.2"
git push origin main
git push origin v1.2.0
```
5. **Update CHANGELOG.md** with a summary of config/schema changes and any adapter API
changes.
---
## Note: This Is a Workspace Template, Not a Plugin
This template does **not** contain a `plugin.yaml` or a `rules/` directory. Those
artifacts belong to Molecule plugins (which extend the agent's capability set at
runtime). A workspace template only provides the **environment** in which the agent
runs. If you need to add new capabilities, create a plugin and reference it via the
`skills` section of `config.yaml`.

158
known-issues.md Normal file
View File

@ -0,0 +1,158 @@
# Known Issues — langgraph Workspace Template
This document tracks unresolved and partially-resolved issues that are known to
occur when running this workspace template. Each entry includes the symptom,
affected versions, workaround, and (where applicable) a link to the upstream or
internal tracker.
---
## 1. langgraph Version Drift Between Template and Platform
**Severity:** High
**Affects:** All template versions prior to aligning `langgraph` pin in
`requirements.txt` with the platform's bundled langgraph runtime.
**Symptom:**
The adapter initialises the langgraph `StateGraph` and immediately crashes with:
```
AttributeError: module 'langgraph' has no attribute 'prebuilt'
```
or, in newer platform releases that bundle langgraph 0.4+:
```
ValueError: Unexpected keyword argument 'store' — this graph does not use checkpointers
```
**Root cause:**
The template pins `langgraph>=0.2.0,<0.3.0` but the platform runtime ships with
`langgraph 0.4.x`. The graph API (constructor args, `checkpointer` vs `store`,
prebuilt agent) changed between 0.2 and 0.4.
**Workaround:**
Edit `requirements.txt` to match the platform's bundled langgraph version:
```bash
# Query the platform for its runtime version
curl -s https://platform.molecule.ai/api/v1/workspaces/{id}/runtime-info \
-H "Authorization: Bearer $MOLECULE_TOKEN" | jq '.langgraph_version'
```
Then update `requirements.txt`:
```
langgraph==<reported_version>
```
**Fix:** The template maintainer will update the pin in every template release that
aligns with a platform upgrade. Always check the release notes before updating the
platform.
---
## 2. `system-prompt.md` Gets Reset on Template Update
**Severity:** Medium
**Affects:** Users who customise `system-prompt.md` directly in the workspace.
**Symptom:**
After pulling a new template version (e.g. `git pull`), the agent's behaviour
changes unexpectedly even though no `config.yaml` changes were made. On inspection,
`system-prompt.md` has been overwritten with the template version.
**Root cause:**
`system-prompt.md` is a template-managed file. When the platform rebuilds the
workspace container it copies the file from the registered template tag, overwriting
any local customisations.
**Workaround — Option A (recommended):**
Do not edit `system-prompt.md` directly. Instead, inject custom instructions via
the `MOLECULE_SYSTEM_PROMPT_OVERRIDE` environment variable. The adapter prepends
this value to the loaded `system-prompt.md` at startup:
```bash
export MOLECULE_SYSTEM_PROMPT_OVERRIDE="You are a helpful assistant with the following additional context: ..."
```
**Workaround — Option B:**
Fork the template and pin to a specific tag. Apply your customisations as patches
on top of that tag.
**Fix:** A future platform release will support a `system_prompt_overlay` field in
`config.yaml` so customisation survives template updates (tracked in internal
ticket MOL-4821).
---
## 3. HEARTBEAT Not Wired in Some langgraph Versions
**Severity:** Medium
**Affects:** Template versions `≤ v1.0.3` running against `langgraph < 0.3.8`.
**Symptom:**
The platform's activity dashboard shows the workspace as "silent" even though the
agent is actively processing tasks. No HEARTBEAT events arrive at the platform.
The adapter log shows:
```
HEARTBEAT emitter disabled: no 'interrupt' channel in graph channels
```
**Root cause:**
In langgraph < 0.3.8, the mechanism to emit out-of-band events from within a graph
step required using a dedicated `"heartbeat"` channel on the `StateGraph`. The adapter
code looked for this channel but did not create it automatically. In 0.3.8+ the
preferred approach is to use `Interrupts`.
**Workaround:**
Add the heartbeat channel explicitly when constructing the graph in `adapter.py`:
```python
builder = StateGraph(AgentState, channels=["heartbeat"])
# ...
graph = builder.compile(interrupt_before=["heartbeat_node"])
```
Or upgrade langgraph to `≥ 0.3.8` where the adapter's auto-wiring logic handles this.
**Fix:** Merged in template v1.0.4. Upgrade to v1.0.4 or later to resolve.
---
## 4. `config.yaml` Schema Mismatch After Platform Upgrade
**Severity:** High
**Affects:** Any workspace that pins `schema_version` below the minimum supported by
the platform after a platform upgrade.
**Symptom:**
The adapter fails to start with:
```
ValidationError: config schema version '1.0' is not supported.
Minimum supported version: '1.1'. Please update config.yaml.
```
**Root cause:**
The Molecule platform increments the minimum supported `schema_version` when it makes
backward-incompatible changes to the config format. Workspaces that pin an older
schema version will fail validation.
**Workaround:**
Immediately after a platform upgrade, edit `config.yaml` and update the
`schema_version` field to the new minimum reported in the platform's release notes:
```yaml
schema_version: "1.1" # change from "1.0" to "1.1"
```
**Prevention:**
The release checklist in `CLAUDE.md` includes a step to review the platform's
minimum schema version before tagging a new template release. Always test against
the target platform version before releasing.
**Fix:** Once `schema_version` is updated, the adapter starts normally. No adapter
code changes are required for schema-only bumps.

228
runbooks/local-dev-setup.md Normal file
View File

@ -0,0 +1,228 @@
# Runbook: Local Development Setup — langgraph Workspace Template
Use this runbook to set up a local development environment for the langgraph workspace
template. It covers cloning, dependency installation, running the adapter outside
Docker, overriding config for dev, building the container, and diagnosing common
problems.
---
## Prerequisites
| Requirement | Version | Notes |
|---|---|---|
| Python | 3.11+ | 3.12 recommended |
| pip | 23+ | |
| Docker | 24+ | |
| Docker Compose | v2 (standalone or compose plugin) | |
| Git | 2.40+ | |
| Access to Molecule platform | Token with `workspace:dev` scope | |
---
## Step 1 — Clone the Repository
```bash
git clone https://github.com/your-org/molecule-ai-workspace-template-langgraph.git
cd molecule-ai-workspace-template-langgraph
```
Always branch off `main` for local development:
```bash
git checkout -b feat/your-feature-name
```
---
## Step 2 — Install Dependencies
```bash
pip install -r requirements.txt
```
If you encounter dependency conflicts with an existing virtual environment, create an
isolated one:
```bash
python -m venv .venv
source .venv/bin/activate # Linux/macOS
# .\.venv\Scripts\Activate.ps1 # Windows PowerShell
pip install -r requirements.txt
```
Verify langgraph is importable:
```bash
python -c "import langgraph; print(langgraph.__version__)"
```
---
## Step 3 — Configure Environment Variables
Copy the example env file and fill in your values:
```bash
cp .env.example .env.local
```
Edit `.env.local`:
```bash
# Required
ANTHROPIC_API_KEY=sk-ant-...
MOLECULE_PLATFORM_URL=https://platform.molecule.ai
MOLECULE_WORKSPACE_ID=ws-dev-local
# Optional — needed only when using persisted checkpointing
CHECKPOINT_DB_URL=postgresql://langgraph:langgraph@localhost:5432/langgraph_checkpoint
# Optional — override adapter log level
LOG_LEVEL=DEBUG
```
> **Security note:** Never commit `.env.local` to version control. It is gitignored
> by the template's `.gitignore`.
---
## Step 4 — Dev Overrides in `config.yaml`
The `config.yaml` shipped in the repo is production-oriented. For local dev,
create `config.dev.yaml` that overrides specific fields:
```yaml
# config.dev.yaml — local development overrides
# Merge with config.yaml using the adapter's --config flag
runtime:
checkpoint:
backend: memory # avoids needing postgres for local dev
model:
temperature: 0.9 # more creative for exploration
max_tokens: 4096 # faster turns, lower cost
observability:
log_level: DEBUG
heartbeat_interval_seconds: 10 # faster feedback during development
```
Apply dev overrides when running locally:
```bash
python adapter.py --config config.yaml --config-override config.dev.yaml
```
The adapter merges `config.dev.yaml` on top of `config.yaml`, with dev values winning
for any conflicting keys.
---
## Step 5 — Run the Adapter Locally
Start the adapter in foreground mode:
```bash
python adapter.py
```
Expected startup output:
```
[molecule.adapter] INFO — resolved config schema_version=1.1
[molecule.adapter] INFO — initialising langgraph runtime version=0.4.2
[molecule.adapter] INFO — loading skills from: /opt/molecule/skills
[molecule.adapter] DEBUG — skill manifest loaded: code_interpreter (langgraph)
[molecule.adapter] DEBUG — skill manifest loaded: browser_search (langgraph)
[molecule.adapter] INFO — HEARTBEAT emitter active (interval=10s)
[molecule.adapter] INFO — workspace ready, polling https://platform.molecule.ai/api/v1/tasks
```
Press `Ctrl+C` to stop. For background operation:
```bash
nohup python adapter.py > adapter.log 2>&1 &
```
---
## Step 6 — Test the Docker Build
Build the dev image:
```bash
docker build \
--build-arg BUILDKIT_INLINE_CACHE=1 \
-t molecule-langgraph-workspace:dev \
.
```
Run a smoke test (adapter starts and emits heartbeat):
```bash
docker run --rm \
--env-file .env.local \
-e LANGGRAPH_CHECKPOINT_NS=local-dev \
molecule-langgraph-workspace:dev \
python -c "
from adapter import MoleculeLanggraphAdapter
a = MoleculeLanggraphAdapter()
a.load_config()
print('smoke test PASSED')
"
```
Full Docker Compose stack (adapter + postgres for checkpointing):
```bash
docker compose up --build
```
Logs:
```bash
docker compose logs -f workspace
```
Teardown:
```bash
docker compose down -v
```
---
## Common Issues Table
| Symptom | Likely Cause | Resolution |
|---|---|---|
| `ModuleNotFoundError: No module named 'langgraph'` | `requirements.txt` not installed | Run `pip install -r requirements.txt` |
| `ValidationError: config schema version '1.0' is not supported` | `schema_version` in `config.yaml` is too old | Update `schema_version` to match platform minimum |
| `AttributeError: module 'langgraph' has no attribute 'prebuilt'` | langgraph version mismatch | Verify `langgraph` version: `pip show langgraph`; align with platform runtime |
| Adapter starts but never receives tasks | Wrong `MOLECULE_PLATFORM_URL` or token expired | Check URL; refresh token: `echo $MOLECULE_TOKEN \| head -c 20` |
| HEARTBEAT never emitted (platform shows "silent") | langgraph < 0.3.8 without heartbeat channel | Upgrade langgraph or add `channels=["heartbeat"]` to StateGraph |
| `postgresql.errors.ConnectionRefused` on startup | `CHECKPOINT_DB_URL` points to unreachable postgres | Ensure postgres is running (`docker compose up -d checkpoint-db`) or set `backend: memory` in dev overrides |
| `docker build` fails with `Step 5/12: RUN pip install...` | Network / pip index issue | Proxy through corporate firewall or mirror: `pip install --index-url https://pypi.org/simple/ -r requirements.txt` |
| `docker run` exits immediately with code 0 | `ANTHROPIC_API_KEY` not set | Pass `--env-file .env.local` or `-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY` |
---
## IDE Setup (VS Code)
```json
// .vscode/settings.json — create in workspace root
{
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
"python.analysis.typeCheckingMode": "basic",
"files.insertFinalNewline": true,
"[python]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "charliermarsh.ruff"
}
}
```
The template includes a `.vscode/launch.json` for attaching the debugger to the
running adapter process (requires `debugpy` in dev dependencies).