Agent integration
How agent nodes run
Every pipeline agent node delegates to a configurable agent runner. The runner is responsible for sending the prompt to a model (with optional thinking level and timeout) and returning text plus optional token usage.
Ripline supports five runner types, selected in priority order:
- Per-node
runner: claude-code— when an agent node setsrunner: "claude-code"and a Claude Code runner is configured. See Using Claude Code as a runner. - Per-node
runner: codex— when an agent node setsrunner: "codex"and a Codex runner is configured. See Using Codex as a runner. - LLM runner — when LLM config is present (Ollama, OpenAI, or Anthropic). See Running with an LLM provider.
- OpenClaw — when running inside an OpenClaw host, the host can provide the default agent runner automatically. See OpenClaw runner below.
- Stub — placeholder response when no runner is configured. Useful for testing pipeline structure.
Running with an LLM provider
Configure a single LLM provider for all agent nodes using environment variables, a config file, or CLI flags.
- Provider:
ollama,openai, oranthropic - Model: e.g.
llama3.2,gpt-4o-mini,claude-3-5-sonnet-20241022 - API keys: Required for OpenAI and Anthropic; optional for Ollama (local). Use
OPENAI_API_KEYorANTHROPIC_API_KEYin the environment, or set in config.
Configuration (precedence: CLI flags > env > config file):
Environment variables
RIPLINE_AGENT_PROVIDER–ollama|openai|anthropicRIPLINE_AGENT_MODEL– model nameRIPLINE_AGENT_BASE_URL– optional (e.g. custom Ollama or OpenAI-compatible endpoint)OPENAI_API_KEY/ANTHROPIC_API_KEY– used when provider is openai/anthropic and no apiKey in config
Config file (optional)
.ripline/agent.json–{ "provider": "ollama", "model": "llama3.2" }(and optionalapiKey,baseURL)- Or
ripline.config.jsonwith anagent(oragentRunner) section with the same shape
CLI flags
ripline run --agent-provider ollama --agent-model llama3.2(and optional--agent-base-url)ripline serve --agent-provider openai --agent-model gpt-4o-mini(useOPENAI_API_KEYfor the key)
Limitations of the LLM runner (this version):
- One provider and model for all agent nodes;
agentIdis ignored. - Session continuity (
resetSession: false) andthinkingare not supported; each call is a single stateless request.
Choosing stub vs LLM vs Claude Code vs Codex runner
Runner selection (global order):
- Per-node
runner: claude-code– If an agent node hasrunner: "claude-code"and a Claude Code runner is configured, that node uses the Claude Code runner (plan or execute mode). - Per-node
runner: codex– If an agent node hasrunner: "codex"and a Codex runner is configured, that node uses the Codex runner (plan or execute mode). - LLM runner – If no per-node built-in code runner is selected and LLM config is present, agent nodes use the LLM runner (Ollama/OpenAI/Anthropic).
- OpenClaw – When Ripline runs inside an OpenClaw host, the host can provide the default agent runner.
- Stub – Otherwise the stub returns a placeholder response.
Per-node rule: Nodes with runner: "claude-code" use the Claude Code runner when claudeCodeRunner is set; nodes with runner: "codex" use the Codex runner when codexRunner is set. If the requested built-in runner is not set, the run fails with a clear "<runner> runner required" message. Nodes without a built-in per-node runner use the default runner available in the current environment.
- CLI (
ripline run): Uses configured standalone runners when present, otherwise the stub. Use--demofor a deterministic stub run. - HTTP server: Uses the runners passed in at startup. To force the stub even when an LLM runner would be available, set
RIPLINE_AGENT_RUNNER=stubbefore starting the server.
Using Claude Code as a runner
When running standalone (not inside OpenClaw), you can configure the Claude Code runner so that agent nodes with runner: "claude-code" invoke the Claude Code SDK (plan-only or full execute) with a configurable working directory.
When to use runner: claude-code vs the LLM runner
- Use Claude Code when you want the model to use tools (read/write files, run commands) in a single node with a fixed
cwd, with either plan (read-only) or execute (edits allowed) mode. - Use the LLM runner when you want a single stateless chat completion per node (no tools, no
cwd).
Plan vs execute mode and security
mode: "plan"– Read-only. The runner uses the SDK withpermissionMode: "plan"and a PreToolUse hook that always deniesWrite,Edit, andMultiEdit(defense-in-depth). Use this for "analyze and suggest" steps.mode: "execute"(default) – The model may use write/edit tools. Use for "implement this" or "apply changes" steps.
cwd injection
- Each node can set
cwd(optional). It supports template interpolation (e.g.{{ run.inputs.repoPath }}). The runner resolves it and validates: the path must be an existing directory and must not contain... Use this to run different nodes in different project roots (e.g. one node per repo). - When using profiles, you can supply paths via profile inputs and reference them in
cwd, e.g.cwd: "{{ run.inputs.projectRoot }}". See Pipelines and profiles.
Configuration
- Environment:
RIPLINE_CLAUDE_CODE_MODE(plan | execute),RIPLINE_CLAUDE_CODE_CWD,RIPLINE_CLAUDE_CODE_MODEL(default model, e.g.claude-sonnet-4-6),RIPLINE_CLAUDE_CODE_MAX_TURNS,RIPLINE_CLAUDE_CODE_TIMEOUT(seconds). - Config file: In
.ripline/agent.jsonorripline.config.json, use a top-levelclaudeCodekey:{ "claudeCode": { "mode": "execute", "cwd": "/path/to/project", "model": "claude-sonnet-4-6", "maxTurns": 10, "timeoutSeconds": 120 } }. The optionalmodelsets the default for all Claude Code nodes; per-nodemodeloverrides it. Example: spec then build queue with Claude Code
# Fragment: spec_then_build_queue with one node on Claude Code (execute) and one on default runner
nodes:
- id: spec
type: agent
runner: claude-code
mode: plan
cwd: "{{ run.inputs.repoPath }}"
prompt: "Analyze the codebase and produce a short spec for the feature."
- id: implement
type: agent
runner: claude-code
mode: execute
cwd: "{{ run.inputs.repoPath }}"
dangerouslySkipPermissions: true # only when global bypass is enabled; use for isolated envs
prompt: "Implement the spec from the previous step. Output a summary to stdout."
edges:
- from: { node: spec }
to: { node: implement }Ensure run.inputs.repoPath is set (e.g. from an input node or upstream artifact) and that Claude Code config (env or file) is present when running standalone.
Using Codex as a runner
When running standalone (not inside OpenClaw), you can configure the Codex runner so that agent nodes with runner: "codex" invoke the local codex exec CLI with a configurable working directory.
When to use runner: codex vs the LLM runner
- Use Codex when you want a tool-using coding agent in a specific
cwd, with either plan (read-only) or execute (workspace-write) mode. - Use the LLM runner when you want a single stateless chat completion per node with no local tool execution.
Plan vs execute mode
mode: "plan"– Runscodex execwith--sandbox read-only.mode: "execute"– Runscodex execwith--sandbox workspace-write.
Configuration
- Environment:
RIPLINE_CODEX_MODE(plan | execute),RIPLINE_CODEX_CWD,RIPLINE_CODEX_MODEL,RIPLINE_CODEX_TIMEOUT(seconds). - Config file: In
.ripline/agent.jsonorripline.config.json, use a top-levelcodexkey:{ "codex": { "mode": "execute", "cwd": "/path/to/project", "model": "gpt-5.4", "timeoutSeconds": 120 } }. Example: implement with Codex
nodes:
- id: implement
type: agent
runner: codex
mode: execute
cwd: "{{ run.inputs.repoPath }}"
prompt: |
Implement the requested change in {{ run.inputs.repoPath }}.
Return a short summary of the files changed.Containers for built-in code runners
Ripline's container layer is generic container infrastructure, not a Claude-specific runtime. If a node or pipeline runs in a container, Ripline provides the container context and the selected runner decides how to execute inside it.
- The container image is user-provided.
- Ripline does not auto-mount runner credentials or binaries into the container.
- Your image must already contain the requested runner (
claudeforrunner: claude-code,codexforrunner: codex) plus any credentials, config files, mounts, or env vars that runner needs. - This applies to both run-level containers and node-level containers.
Bypass permissions mode (advanced)
By default, execute mode uses permissionMode: "dontAsk" with an explicit allowedTools whitelist and disallowedTools denylist. For fully autonomous headless execution in an isolated environment (e.g. a container or VM, or CI/CD), you can opt in to bypass permissions mode. In this mode the SDK does not prompt for tool approval and allowedTools is not enforced by the SDK (a known SDK behavior); disallowedTools is still applied as a last-resort constraint.
When it's appropriate: Only in isolated environments where the host is already scoped (container, VM, dedicated CI runner). Do not use bypass on a shared or personal machine.
How to enable (user-level only; not configurable from pipeline YAML or profiles):
- User config: In
~/.ripline/config.json, set"claudeCode": { "allowDangerouslySkipPermissions": true }. - Environment: Set
RIPLINE_CLAUDE_CODE_DANGEROUSLY_SKIP_PERMISSIONS=true(useful in CI/CD).
Per-node opt-in (recommended): For safety, bypass runs only for nodes that explicitly set dangerouslySkipPermissions: true in the pipeline YAML. Even with global bypass enabled, nodes that omit this property use default execute mode (dontAsk + allowedTools). This limits blast radius: only the nodes you mark get full autonomy.
Logging (Claude Code runner)
The Claude Code runner writes diagnostic logs to stderr (and, when running a stored run, to <runsDir>/<runId>/log.txt):
- Stream message logging — Every message from the Claude Agent SDK stream is logged with
typeandsubtype(e.g.system/init,assistant,user,result) so you can see turns in real time. - Result message dump — When a
type=resultmessage arrives, the full object is logged (truncated to 2000 chars). - Rich error detail on failure — On non-success (e.g.
error_max_turns), the runner logssubtype,errors, and a result snippet, then throws with that detail. - Config at startup — Set
RIPLINE_LOG_CONFIG=1to log the effective config once per invocation:maxTurns,timeoutMs,mode,cwd. Omit or leave unset to keep startup quiet.
To view logs for a run: use ripline logs <runId> (or ripline logs <runId> --follow to stream), or GET /runs/:runId/logs / GET /runs/:runId/logs/stream via the HTTP API. See HTTP API – run logs.
Activation rules: Bypass is used only when all of the following are true: the global flag is enabled (config or env), the node sets dangerouslySkipPermissions: true, the node mode is "execute", and cwd is explicitly set (in config or node params) and resolves to an existing directory. Otherwise the runner falls back to default execute mode and logs why bypass was not activated.
What does not change: Plan mode is never affected. cwd validation, maxTurns ceiling, timeout, and the PreToolUse hook behavior are unchanged. A warning is always printed to stderr when bypass is active; it cannot be suppressed.
Skills
Agent nodes support two complementary skill mechanisms, both referenced with the same skills array.
MCP server skills
An MCP server skill wires a tool server (like Playwright) into the agent's session. These are defined in the skills registry in ripline.config.json or a profile:
{
"skills": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
},
"brave-search": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
"env": { "BRAVE_API_KEY": "your-key" }
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "your-token" }
}
}
}Reference them on any node:
- id: implement
type: agent
runner: claude-code
mode: execute
skills: [playwright, brave-search, github]
prompt: "..."Text skills
A text skill is a markdown file that teaches the agent how to use a CLI tool, API, or workflow pattern. The file's content is injected into the agent's prompt as a <skills> block before the main prompt.
Location: ~/.ripline/skills/<skill-name>.md (configurable via skillsDir in ~/.ripline/config.json)
Example — ~/.ripline/skills/github-cli.md:
# GitHub CLI (gh)
Use `gh` for all GitHub operations. Never construct raw `git` API calls when `gh` can handle it.
## Key commands
- `gh pr list --state open` — list open PRs
- `gh pr create --title "..." --body "..." --base main` — open a PR
- `gh pr merge <number> --squash` — merge a PR
- `gh issue create --title "..." --body "..."` — create an issue
- `gh issue list --assignee @me` — list your issues
- `gh run list` — list recent workflow runs
- `gh run watch <id>` — watch a run in real time
## Auth
Assumes `gh auth login` has been run. If a command fails with auth errors, stop and report — do not attempt to re-auth.Example — ~/.ripline/skills/aws-cli.md:
# AWS CLI
Use the `aws` CLI for all AWS operations.
## Common patterns
- `aws s3 ls s3://bucket-name/` — list bucket contents
- `aws s3 cp file.txt s3://bucket/path/` — upload a file
- `aws lambda invoke --function-name my-fn out.json` — invoke a Lambda
- `aws logs tail /aws/lambda/my-fn --follow` — stream logs
## Credentials
Credentials are resolved from the environment (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_DEFAULT_REGION`) or from `~/.aws/credentials`. Never hardcode credentials.When a node references skills: [github-cli, aws-cli], both files are read and injected before the prompt:
- id: deploy
type: agent
runner: claude-code
mode: execute
skills: [github-cli, aws-cli]
prompt: |
Open a PR for the current branch and deploy the latest Lambda after it merges.A skill can be both a text file AND an MCP server. If github-cli has an entry in the registry (for MCP tool access) and a github-cli.md file in the skills directory, both are applied: the MCP server is wired in and the markdown is injected into the prompt.
Discovery: Ripline checks for <skillName>.md in the skills directory for every name in the skills array. If no file exists for a given name, that name is silently skipped (it may still resolve as an MCP server skill). No error is thrown for missing text skill files.
SKILLS.md (legacy / per-project)
If the agent's effective cwd contains a SKILLS.md file, its content is also injected. This is an older per-project mechanism; named text skills in ~/.ripline/skills/ are preferred for reusable cross-pipeline knowledge.
Context isolation (sessions)
To avoid context bleed between agent nodes:
- Default (isolation): Each agent node runs with a new unique session ID (UUID). The agent only sees the current prompt and inputs; no prior turns from other nodes.
- Continuity (opt-in): Set
resetSession: falseon an agent node to use the run-level session. The runner generates one sharedsessionIdper pipeline run and passes it to every node that hasresetSession: false, so those nodes share the same conversation.
OpenClaw runner
This section describes the optional OpenClaw integration. Ripline works fully standalone without OpenClaw. See OpenClaw Integration for plugin setup.
When the pipeline plugin is loaded by an OpenClaw host, the host passes a runtime API. The plugin creates an agent runner that calls the OpenClaw agent subprocess via runtime.system.runCommandWithTimeout. All pipeline agent nodes then use the platform's configured models, tools, and sandbox automatically.
Agent JSON envelope
The OpenClaw runner invokes:
openclaw agent --json --agent <agentId> --session <sessionId> [--thinking <level>] [--timeout <seconds>]with the prompt on stdin. The sessionId is either a new UUID per node (context isolation) or the run-level session ID (when the node has resetSession: false). It expects stdout to be a single JSON object:
text(string, required): model response text.tokenUsage(optional):{ "input": number, "output": number }.
Any non-zero exit code or invalid JSON is surfaced as an error; the run record is updated (status errored, waitFor cleared) with a clear message.
Limitations when running inside OpenClaw
- Built-in standalone runners like
claude-codeandcodexare not available. Agent nodes that request them will fail with a clear"<runner> runner required"message. agentIdon each node selects the OpenClaw agent persona/config to invoke.thinkingandtimeoutare passed through to the OpenClaw agent CLI.
References
src/pipeline/executors/agent.ts– agent node executor andAgentRunnertypesrc/integrations/openclaw/openclaw-runner.ts–createOpenClawAgentRunner(api)andOpenClawPluginApisrc/llm-agent-runner.ts–createLlmAgentRunner(config)for Ollama/OpenAI/Anthropicsrc/claude-code-runner.ts–createClaudeCodeRunner(config)for Claude Code (plan/execute)src/codex-runner.ts–createCodexRunner(config)for Codex (plan/execute)src/agent-runner-config.ts– config resolution (env, file, plugin)src/interfaces/– pluggable interfaces:EventSinkandRunnerRegistry
Node options
resetSession(optional, defaulttrue): Whentrueor omitted, the node runs with a new session (context isolation). Whenfalse, the node uses the run-levelsessionIdfor conversation continuity.sessionId(optional, on node): Reserved for future use (e.g. explicit "use this session" override). Run-level session is set by the runner; nodes withresetSession: falsereceive it via execution context.runner(optional): Set to"claude-code"or"codex"to use that built-in runner for this node when configured; otherwise Ripline uses the default runner available in the current environment.mode(optional, whenrunner: "claude-code"or"codex"):"plan"(read-only) or"execute"(default).model(optional, whenrunner: "claude-code"or"codex"): Model to use for this node. Overrides the default from config or CLI. Omit to use the default.cwd(optional, whenrunner: "claude-code"or"codex"): Working directory for the run; supports template interpolation (e.g.{{ run.inputs.repoPath }}). Must be an existing directory and must not contain...dangerouslySkipPermissions(optional): Forrunner: "claude-code", set totrueto allow bypass permissions for this node when global bypass is enabled (~/.ripline/config.jsonorRIPLINE_CLAUDE_CODE_DANGEROUSLY_SKIP_PERMISSIONS=true). Forrunner: "codex", set totrueto allow bypass approvals/sandbox for this node when global bypass is enabled (~/.ripline/config.jsonorRIPLINE_CODEX_DANGEROUSLY_SKIP_PERMISSIONS=true).