molecule-ai-workspace-templ.../CLAUDE.md
documentation-specialist 87032e11cb
Some checks failed
CI / validate (pull_request) Failing after 0s
CI / validate (push) Failing after 0s
docs(install): migrate git clone URL to git.moleculesai.app (#37)
Two refs to migrate:
- CLAUDE.md:147 (Setup section)
- runbooks/local-dev-setup.md:19 (Step 1)

Note: this repo is PRIVATE on Gitea. The clone URL uses the canonical
Gitea path; the runbook reader handles auth via SSH key, git
credential helper, or a personal token. Same convention as the rest
of the workspace-template + plugin-* PRs in the #37 series.

Refs: molecule-ai/internal#37, molecule-ai/internal#38
2026-05-07 00:40:47 -07:00

211 lines
6.4 KiB
Markdown

# Molecule AI Workspace Template — gemini-cli Runtime
## Purpose
This template provides a self-contained Docker workspace for the gemini-cli agent runtime used by Molecule AI platforms. It packages a configured gemini-cli agent inside a Docker container, wired to connect back to the Molecule AI platform via `adapter.py`.
It is NOT a plugin. It has no `plugin.yaml` and no `rules/` directory. It is a workspace *environment* — a Dockerfile, a runtime config, and an adapter — that the platform spins up on behalf of an agent.
## Key Files
### `config.yaml`
Runtime configuration for the gemini-cli agent.
```yaml
schema_version: "1"
runtime:
agent: gemini-cli
model: gemini-2.5-flash
api_key_env: GEMINI_API_KEY
skills:
enabled: true
list:
- name: file-search
path: /workspace/skills/file-search
- name: web-fetch
path: /workspace/skills/web-fetch
adapter:
platform_url: https://platform.molecule.ai
workspace_id_env: WORKSPACE_ID
timeout_seconds: 30
```
- `model` selects the Gemini model variant. Common values: `gemini-2.0-flash`, `gemini-2.5-flash`, `gemini-2.5-pro`.
- `api_key_env` names the env var that holds the Gemini API key at container startup. The key itself is injected by the Molecule AI platform or set locally during dev.
- `skills` lists local skill directories to expose to the agent. These are loaded at startup by gemini-cli.
### `adapter.py`
Thin shim that translates Molecule AI platform events into gemini-cli tool calls and streams responses back. Key entry points:
```python
# adapter.py
import os, sys
def connect(platform_url: str, workspace_id: str, timeout: int = 30):
"""Called by the platform shim to hand off a session to gemini-cli."""
...
def stream_response(session_id: str, prompt: str) -> str:
"""Blocking call: send prompt to gemini-cli, stream token back."""
...
```
`connect()` is invoked once per session by the platform harness inside the container. `stream_response()` is called for each agent turn.
### `system-prompt.md`
Injected at container startup into the gemini-cli prompt stack. This is the canonical place to set the agent's persona, guardrails, and tool whitelist. gemini-cli concatenates it before its default system message.
```markdown
# System Prompt — Molecule AI gemini-cli Agent
You are a research agent running inside a Molecule AI workspace.
You have access to the following tools: file-search, web-fetch.
Do not call tools outside this list without explicit user approval.
...
```
### `requirements.txt`
Pinned Python dependencies for the adapter and any skill loaders.
```
gemini-cli>=1.0.0
molecule-ai-adapter>=2.1.0
httpx>=0.27.0
pydantic>=2.0.0
```
### `Dockerfile`
Builds the workspace image. Key stages:
```dockerfile
FROM python:3.11-slim
WORKDIR /workspace
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN mkdir -p /workspace/skills
ENV GEMINI_API_KEY=""
ENV WORKSPACE_ID="local-dev"
CMD ["python", "-m", "adapter"]
```
The `CMD` invokes the adapter module, which bootstraps gemini-cli and connects to the platform. To override the startup command locally:
```bash
docker build -t molecule-gemini-cli:dev .
docker run --rm \
-e GEMINI_API_KEY="$(cat ~/.gemini-api-key)" \
-e WORKSPACE_ID="dev-001" \
molecule-gemini-cli:dev
```
## Runtime Config Conventions
### Gemini Model Selection
Set `runtime.model` in `config.yaml`. gemini-cli resolves this to a Vertex AI / AI Studio model name at startup. If the model string does not match a known alias, gemini-cli exits with:
```
ValueError: Unknown model 'gemini-99-pro'. Did you mean 'gemini-2.0-pro'?
```
### API Key Handling
The Gemini API key is injected via the `GEMINI_API_KEY` env var. The platform sets this before `docker run`. Never bake API keys into the image. In local dev, pass it with `--build-arg` or `-e`.
```bash
# Build-time secret (buildkit needed for --build-arg secrecy)
docker build --build-arg GEMINI_API_KEY -t molecule-gemini-cli:dev .
# Runtime secret (recommended for local dev)
docker run --rm -e GEMINI_API_KEY="$GEMINI_API_KEY" molecule-gemini-cli:dev
```
### Skill Loading from config.yaml
gemini-cli loads skills listed under `skills.list` in `config.yaml` at startup. Each entry requires `name` and `path`. If the `path` does not exist, gemini-cli logs a warning and skips the skill:
```
WARN: skill 'file-search' path /workspace/skills/file-search not found, skipping
```
The skill directories must be volume-mounted or present in the image.
## Dev Setup
```bash
# 1. Clone
git clone https://git.moleculesai.app/molecule-ai/molecule-ai-workspace-template-gemini-cli.git
cd molecule-ai-workspace-template-gemini-cli
# 2. Install dependencies
pip install -r requirements.txt
# 3. Build image
docker build -t molecule-gemini-cli:dev .
# 4. Config override for local dev
# Edit config.yaml or set environment variables:
export GEMINI_API_KEY="$(cat ~/.gemini-api-key)" # not in the repo
export WORKSPACE_ID="dev-local"
# 5. Smoke test
docker run --rm \
-e GEMINI_API_KEY="$GEMINI_API_KEY" \
-e WORKSPACE_ID="$WORKSPACE_ID" \
molecule-gemini-cli:dev python -c "
from adapter import connect, stream_response
connect('http://localhost:8080', 'dev-local')
print(stream_response('test-session', 'ping'))
"
# 6. Verify adapter connects to platform
docker run --rm \
-e GEMINI_API_KEY="$GEMINI_API_KEY" \
-e WORKSPACE_ID="$WORKSPACE_ID" \
-e ADAPTER_PLATFORM_URL="https://platform.molecule.ai" \
molecule-gemini-cli:dev python -c "from adapter import connect; connect()"
```
## Testing
```bash
# Smoke test — runs adapter.connect() and exits 0 on success
docker run --rm \
-e GEMINI_API_KEY="$GEMINI_API_KEY" \
-e WORKSPACE_ID="smoke-test" \
molecule-gemini-cli:dev python -c "
import sys, os
from adapter import connect
try:
connect(os.environ['ADAPTER_PLATFORM_URL'], os.environ['WORKSPACE_ID'])
print('OK')
sys.exit(0)
except Exception as e:
print(f'FAIL: {e}')
sys.exit(1)
"
```
## Release Process
1. **Schema version bump** — increment `schema_version` in `config.yaml` following the platform's compatibility matrix. Breaking changes require a major version bump.
2. **Tag** — tag the commit with the new version:
```bash
git tag -a v1.2.0 -m "release: schema v1.2, add skill hot-reload"
git push origin main --tags
```
3. The CI pipeline builds and pushes the image to the registry on tags matching `v*`.
4. Update the platform workspace registry entry to point at the new tag.