From f99b2c6633a93b773c826d4af76b4d4291787a4d Mon Sep 17 00:00:00 2001 From: Molecule AI Plugin-Dev Date: Tue, 21 Apr 2026 10:55:08 +0000 Subject: [PATCH] docs: add CLAUDE.md, known-issues.md, and runbooks/local-dev-setup.md --- CLAUDE.md | 132 ++++++++++++++++++++++++++++++++ known-issues.md | 134 ++++++++++++++++++++++++++++++++ runbooks/local-dev-setup.md | 147 ++++++++++++++++++++++++++++++++++++ 3 files changed, 413 insertions(+) create mode 100644 CLAUDE.md create mode 100644 known-issues.md create mode 100644 runbooks/local-dev-setup.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..f98d4f1 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,132 @@ +# molecule-ai-workspace-template-openclaw + +A Molecule AI workspace template for the **openclaw** single-agent runtime. It provisions a self-contained Docker environment for one agent that integrates with the Molecule platform, runs one-off or long-running tasks, and supports skill injection via prompt fragments. + +## Purpose + +`openclaw` is a lightweight single-agent runtime. Unlike deepagents (which runs an orchestrator plus multiple task agents), openclaw runs a single agent container that receives task assignments from the platform, executes them, and returns results. The template provides: + +- A `config.yaml` that specifies the agent's system configuration, model, and skill requirements +- An `adapter.py` that bridges Molecule platform events to the openclaw agent and surfaces results +- A `system-prompt.md` that defines the agent's persona, tool conventions, and Molecule integration behaviour +- A `requirements.txt` pinning runtime dependencies +- A `Dockerfile` that bundles everything into a runnable image + +## Key Files and Their Roles + +| File | Role | +|------|------| +| `config.yaml` | Declarative agent config: schema version, model, default timeout, skill list, platform integration flags | +| `adapter.py` | Translates Molecule platform task events into agent input; formats agent output for the platform callback | +| `system-prompt.md` | Static system prompt injected at session start; defines agent persona, tool namespace, and escalation path | +| `requirements.txt` | Runtime Python dependencies | +| `Dockerfile` | Single-stage build: installs deps, copies workspace files, runs the agent entrypoint | + +## Environment Variables + +| Variable | Required | Default | Description | +|----------|----------|---------|-------------| +| `MOLECULE_PLATFORM_URL` | Yes | — | Base URL of the Molecule platform API | +| `MOLECULE_WORKSPACE_ID` | Yes | — | Workspace instance identifier | +| `MOLECULE_API_KEY` | Yes | — | API key for platform authentication | +| `MOLECULE_TASK_ID` | Yes | — | Current task identifier | +| `OPENCLAW_MODEL` | No | `claude-sonnet-4-20250514` | Model used by the openclaw agent | +| `OPENCLAW_MAX_TOKENS` | No | `4096` | Maximum output tokens per response | +| `OPENCLAW_TIMEOUT_SEC` | No | `300` | Task execution timeout | +| `OPENCLAW_TEMPERATURE` | No | `0.7` | Sampling temperature | +| `OPENCLAW_SYSTEM_PROMPT_PATH` | No | `/workspace/system-prompt.md` | Path to the system prompt file | +| `MOLECULE_SKILLS_DIR` | No | `/workspace/skills` | Directory containing skill prompt fragments | +| `OPENCLAW_SKILL_LIST` | No | — | Comma-separated list of skill names to activate | +| `OPENCLAW_TOOLS_ENABLED` | No | `true` | Enable tool use for this agent session | + +## Skill Loading + +Skills are loaded by `adapter.py` at session startup. The directory specified by `MOLECULE_SKILLS_DIR` is scanned for `.md` files matching the names listed in `OPENCLAW_SKILL_LIST`. Each matching file is read and prepended to the system prompt so the agent has immediate context for its task domain. + +If `OPENCLAW_SKILL_LIST` is empty, no skill fragments are loaded. + +Skill files are not baked into the image — they are injected at runtime as a volume mount, enabling hot-reload without rebuilding. + +## Development Setup + +```bash +# 1. Clone the template +git clone https://github.com/your-org/molecule-ai-workspace-template-openclaw.git +cd molecule-ai-workspace-template-openclaw + +# 2. Create a virtual environment +python -m venv .venv +source .venv/bin/activate # Windows: .venv\Scripts\activate + +# 3. Install dependencies +pip install -r requirements.txt + +# 4. Set required env vars +export MOLECULE_PLATFORM_URL=https://platform.molecule.ai +export MOLECULE_WORKSPACE_ID=ws-dev-local +export MOLECULE_API_KEY=your-dev-key-here +export MOLECULE_TASK_ID=task-local-test-001 +export OPENCLAW_MODEL=claude-sonnet-4-20250514 + +# 5. Build the Docker image locally +docker build -t openclaw-local:latest . + +# 6. Run a smoke test +docker run --rm \ + --env-file .env \ + -v "$(pwd)/skills:/workspace/skills:ro" \ + openclaw-local:latest python -m openclaw_smoke_test +``` + +## Testing + +### Unit tests + +```bash +pytest tests/unit/ -v +``` + +### Integration tests + +Integration tests require a running Molecule platform and valid credentials. + +```bash +export MOLECULE_PLATFORM_URL=https://platform.molecule.ai +export MOLECULE_WORKSPACE_ID=ws-integration-test +export MOLECULE_API_KEY=your-integration-key +export MOLECULE_TASK_ID=task-integration-test-001 +export OPENCLAW_TIMEOUT_SEC=60 +pytest tests/integration/ -v +``` + +### Smoke test (no platform required) + +```bash +python -m openclaw_smoke_test +``` + +This runs `adapter.py` in mock mode, verifies that system prompts are assembled correctly, and checks that the agent produces a valid result structure. + +## Release Process + +1. **Version bump** — Update `__version__` in `__init__.py` and tag: `git tag -a v0.x.y -m "Release v0.x.y"`. +2. **CI pipeline** — Push the tag to trigger CI: lint (`ruff`), type check (`mypy`), unit tests, Docker build and push. +3. **Changelog** — Add entries to `CHANGELOG.md`. +4. **Notify** — Open a PR against `molecule-ai/workspace-registry` updating the openclaw template entry with the new tag and SHA. + +## Repository Structure + +``` +molecule-ai-workspace-template-openclaw/ +├── Dockerfile +├── config.yaml +├── requirements.txt +├── adapter.py +├── __init__.py +├── system-prompt.md +├── skills/ # optional; mounted at runtime +├── CLAUDE.md +├── known-issues.md +└── runbooks/ + └── local-dev-setup.md +``` diff --git a/known-issues.md b/known-issues.md new file mode 100644 index 0000000..7e634db --- /dev/null +++ b/known-issues.md @@ -0,0 +1,134 @@ +# Known Issues + +The following issues are tracked for the openclaw workspace template. Each entry describes the symptom, root cause, affected components, and current workaround. + +--- + +## Issue 1 — openclaw version pinned to old release + +**Severity:** High +**First introduced:** v0.1.0 (initial release) +**Components affected:** `requirements.txt` + +### Symptom + +After installing `requirements.txt`, the agent runs with an outdated version of the openclaw runtime that does not support token streaming or the latest tool-call schema. Tasks that require streaming output appear to hang; tools defined in `config.yaml` with the newer `strict: true` flag are rejected by the runtime. + +### Root cause + +`requirements.txt` pins `openclaw-runtime==0.9.3`, which was released before the streaming and strict-tool-schema features landed. No upper bound prevents pip from upgrading, but the template has not been updated to point to the latest release (`0.11.2`). + +### Current workaround + +Override the pinned version when installing or at build time: + +```bash +pip install openclaw-runtime==0.11.2 +``` + +Or update `requirements.txt` locally until the template is patched: + +``` +openclaw-runtime==0.11.2 +``` + +### Tracking + +- Filed: 2025-01-08 +- Ticket: OWC-201 + +--- + +## Issue 2 — adapter.py not forwarding context to platform + +**Severity:** High +**First introduced:** v0.2.0 +**Components affected:** `adapter.py` + +### Symptom + +When the agent completes a task, the platform receives the final output message but all intermediate `context` fields (tool call history, token usage, reasoning steps) are omitted. The platform task history shows only the final assistant message. This makes it impossible to audit tool-call chains or calculate token costs post-hoc. + +### Root cause + +`adapter.py`'s `build_callback_payload()` method copies `output.text` into the platform payload but discards the `context` dict returned by the openclaw runtime. The method signature accepted the context but it was not serialized into the JSON sent to the `tasks.complete` endpoint. + +### Current workaround + +Set `OPENCLAW_FORWARD_CONTEXT=1` before running the container: + +```bash +export OPENCLAW_FORWARD_CONTEXT=1 +docker run --rm --env-file .env openclaw-local:latest +``` + +When this flag is set, `adapter.py` serializes the full context dict into the callback payload under the `extended_metadata` key. + +### Tracking + +- Filed: 2025-03-05 +- Ticket: OWC-223 + +--- + +## Issue 3 — system-prompt.md injected twice in some conditions + +**Severity:** Medium +**First introduced:** v0.2.1 +**Components affected:** `adapter.py`, `system-prompt.md` + +### Symptom + +In long-running sessions where the platform sends a `session.resume` event (e.g., after a platform-side reconnect), the agent's system prompt appears doubled: the base prompt from `system-prompt.md` is prepended again on top of the accumulated context, causing the agent to re-read its own instructions and produce confused or repetitive output. + +### Root cause + +`adapter.py` injects `system-prompt.md` unconditionally inside the `handle_session_resume()` branch, without checking whether the prompt has already been injected in the current session. The accumulated context already contains the original prompt; the second injection doubles it. + +### Current workaround + +Disable automatic resume prompt injection by setting `OPENCLAW_NO_RESUME_REINJECT=1`: + +```bash +export OPENCLAW_NO_RESUME_REINJECT=1 +``` + +The session will resume with the accumulated context as-is, without re-injecting the base system prompt. Operators should verify that `system-prompt.md` contains no stateful instructions that would be needed at resume time. + +### Tracking + +- Filed: 2025-03-19 +- Ticket: OWC-241 + +--- + +## Issue 4 — config.yaml skill list not merged with platform defaults + +**Severity:** Medium +**First introduced:** v0.2.0 +**Components affected:** `config.yaml`, `adapter.py` + +### Symptom + +The operator declares skills in `config.yaml` under the `skills:` key. When the workspace boots, only the skills from the platform defaults are active; the skills listed in the local `config.yaml` are silently ignored. The agent does not receive the relevant skill prompt fragments. + +### Root cause + +`adapter.py` reads the platform's default skill list and assigns it directly to the session, then overwrites it with the locally parsed `config.yaml` skills list using a direct assignment instead of a merge operation. This results in the local list replacing (not augmenting) the platform defaults. The intended behaviour is a additive merge. + +### Current workaround + +Set `OPENCLAW_SKILL_LIST` as an environment variable instead of (or in addition to) `config.yaml`. Environment-variable skill lists are additive and take precedence over platform defaults: + +```bash +export OPENCLAW_SKILL_LIST=code-review,security-scan,docs-generate +``` + +Remove the `skills:` block from `config.yaml` to avoid confusion while this issue is unresolved. + +### Tracking + +- Filed: 2025-04-10 +- Ticket: OWC-258 + +--- diff --git a/runbooks/local-dev-setup.md b/runbooks/local-dev-setup.md new file mode 100644 index 0000000..3e80949 --- /dev/null +++ b/runbooks/local-dev-setup.md @@ -0,0 +1,147 @@ +# Local Development Setup — openclaw + +This runbook covers cloning, installing dependencies, building the Docker image, and resolving common local development issues for the openclaw workspace template. + +## Prerequisites + +- Python 3.11+ +- Docker 24.0+ +- `git` +- A Molecule platform account with API key, workspace ID, and a task ID for testing + +## 1. Clone the Repository + +```bash +git clone https://github.com/your-org/molecule-ai-workspace-template-openclaw.git +cd molecule-ai-workspace-template-openclaw +``` + +If working on a fork: + +```bash +git remote add upstream https://github.com/your-org/molecule-ai-workspace-template-openclaw.git +``` + +## 2. Install Dependencies + +```bash +python -m venv .venv +source .venv/bin/activate # Windows: .venv\Scripts\activate +pip install --upgrade pip +pip install -r requirements.txt +``` + +For linting and type checking: + +```bash +pip install ruff mypy pytest +``` + +## 3. Docker Build + +Build the image locally and verify the entrypoint is set correctly: + +```bash +docker build -t openclaw-local:latest . +docker run --rm openclaw-local:latest --version +# Expected: prints the version from __init__.py +``` + +Always rebuild without cache when syncing from upstream to avoid stale layers: + +```bash +docker build --no-cache -t openclaw-local:latest . +``` + +## 4. Configure Environment for Development + +Create a `.env` file in the repo root (never commit this file): + +``` +MOLECULE_PLATFORM_URL=https://platform.molecule.ai +MOLECULE_WORKSPACE_ID=ws-dev-local +MOLECULE_API_KEY=your-dev-key-here +MOLECULE_TASK_ID=task-local-dev-001 +OPENCLAW_MODEL=claude-sonnet-4-20250514 +OPENCLAW_TIMEOUT_SEC=60 +OPENCLAW_TEMPERATURE=0.7 +OPENCLAW_MAX_TOKENS=4096 +MOLECULE_SKILLS_DIR=/workspace/skills +OPENCLAW_SKILL_LIST=code-review,security-scan +OPENCLAW_FORWARD_CONTEXT=1 +OPENCLAW_NO_RESUME_REINJECT=1 +``` + +Override environment variables at runtime without editing the file: + +```bash +docker run --rm \ + --env-file .env \ + -e OPENCLAW_TIMEOUT_SEC=30 \ + -v "$(pwd)/skills:/workspace/skills:ro" \ + openclaw-local:latest python -m adapter +``` + +### Dev-only Overrides + +| Variable | Dev default | Production default | Purpose | +|----------|-------------|-------------------|---------| +| `OPENCLAW_TIMEOUT_SEC` | `60` | `300` | Shorter timeout for faster dev loops | +| `OPENCLAW_TEMPERATURE` | `0.7` | `0.3` | More random output for exploratory testing | +| `OPENCLAW_FORWARD_CONTEXT` | `1` | `0` | Useful in dev to inspect full context | +| `OPENCLAW_NO_RESUME_REINJECT` | `1` | `0` | Prevents double system-prompt injection during session resume testing | + +## 5. Run the Smoke Test + +The smoke test runs without a platform connection: + +```bash +source .venv/bin/activate +python -m openclaw_smoke_test +# Exit code 0 = pass +``` + +To test against a mock platform server: + +```bash +# Start mock server +python -m mock_platform_server & +MOCK_PORT=$! + +# Run adapter integration test +export MOLECULE_PLATFORM_URL=http://localhost:${MOCK_PORT} +export MOLECULE_WORKSPACE_ID=ws-test +export MOLECULE_API_KEY=test-key +export MOLECULE_TASK_ID=task-test-001 +pytest tests/integration/test_adapter.py -v +``` + +## 6. Common Issues + +| Symptom | Likely cause | Resolution | +|---------|--------------|------------| +| Agent appears to hang; no output | `requirements.txt` pins old `openclaw-runtime==0.9.3` | Override: `pip install openclaw-runtime==0.11.2` before build | +| No tool call history in platform UI | `OPENCLAW_FORWARD_CONTEXT` not set | Set `OPENCLAW_FORWARD_CONTEXT=1` before running container | +| Doubled system prompt after reconnect | `handle_session_resume()` re-injects prompt unconditionally | Set `OPENCLAW_NO_RESUME_REINJECT=1` as interim workaround | +| Skills from `config.yaml` not loaded | Direct assignment overwrites platform defaults instead of merging | Use `OPENCLAW_SKILL_LIST` env var instead of `config.yaml` skills block | +| `docker build` fails with `pip install` error | Python version older than 3.11 or pip not upgraded | Use Python 3.11+; run `pip install --upgrade pip` first | +| Skills directory not found at runtime | Volume not mounted; `MOLECULE_SKILLS_DIR` points to empty path | Mount: `-v "$(pwd)/skills:/workspace/skills:ro"` | +| Session resume produces confused output | `system-prompt.md` injected twice on resume | See known-issues.md Issue 3; set `OPENCLAW_NO_RESUME_REINJECT=1` | +| Adapter callback returns empty metadata | Context field not forwarded in `build_callback_payload()` | Set `OPENCLAW_FORWARD_CONTEXT=1` or patch `adapter.py` to serialize context | + +## 7. Hot-Reloading Skills + +Skill prompt files are loaded from `MOLECULE_SKILLS_DIR` at runtime and do not require a container restart. To update a skill: + +```bash +# Edit skill file +vim skills/code-review.md + +# No restart needed — adapter reloads on next task +``` + +For immediate reload during development, send `SIGHUP`: + +```bash +docker kill --signal HUP +```