docs: add CLAUDE.md, known-issues.md, and runbooks/local-dev-setup.md
This commit is contained in:
parent
f18d7b36d8
commit
f99b2c6633
132
CLAUDE.md
Normal file
132
CLAUDE.md
Normal file
@ -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
|
||||
```
|
||||
134
known-issues.md
Normal file
134
known-issues.md
Normal file
@ -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
|
||||
|
||||
---
|
||||
147
runbooks/local-dev-setup.md
Normal file
147
runbooks/local-dev-setup.md
Normal file
@ -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 <container_id>
|
||||
```
|
||||
Loading…
Reference in New Issue
Block a user