How to Integrate LoopX with CI Systems, Chat Bots, and Custom Tools
LoopX integrates with external tools through a three-layer architecture—Kernel, Capability/Extension, and Provider/Adapter—that lets you connect any CI pipeline, Lark bot, or custom script without copying code into each project.
LoopX acts as a provider-neutral, local-first control plane designed to be shared across many projects. According to the huangruiteng/loopx source code, you can attach any external system while preserving durable guarantees like objective tracking, quota enforcement, and evidence logging. This guide walks through the six-step integration process using actual implementation patterns from loopx/runtime.py and loopx/extensions/.
Understanding the LoopX Integration Architecture
Before writing adapters, you need to understand how LoopX separates concerns across three layers:
| Layer | Responsibility | Key Entry Point |
|---|---|---|
| Kernel | Stores durable state—objectives, gates, todos, evidence, quota—and enforces loop contracts | loopx/runtime.py and loopx/state_* modules |
| Capability/Extension | Defines caller-outcome contracts, normalizes provider output, validates transitions | loopx/extensions/ and loopx/capabilities/ directories |
| Provider/Adapter | Executes actual work (CI calls, bot messages, scripts) and returns read-back payloads | Project-specific plugins like loopx/extensions/lark/ adapters |
This separation means your integration code stays thin. The kernel handles durability; you only implement the adapter contract.
Step 1: Install LoopX as a Shared Base
LoopX is designed to be installed once and reused everywhere. The scripts/install-local.sh script puts the loopx binary on your PATH and registers a global Codex skill.
git clone https://github.com/huangruiteng/loopx ~/loopx
~/loopx/scripts/install-local.sh
loopx doctor
Run loopx doctor to verify installation. This single base serves every project on your machine—no vendoring required.
Step 2: Connect Your Project to LoopX
From any project directory, run loopx connect (or loopx bootstrap for initial setup). This creates:
.loopx/registry.json— adapter mappings and goal metadata.codex/goals/<goal-id>/ACTIVE_GOAL_STATE.md— read-only runtime state
cd /path/to/your-project
loopx connect
loopx status
The connection is idempotent—safe to re-run. For first-time setup with explicit parameters:
loopx bootstrap \
--goal-id project-goal \
--objective "Add LoopX control plane to this repo" \
--goal-doc GOAL.md
This pattern appears in docs/integration.md lines 90–100.
Step 3: Build a Project-Specific Adapter
Adapters are thin Python modules that:
- Read the active goal state from
.codex/goals/<goal-id>/ACTIVE_GOAL_STATE.md - Execute the external tool
- Print a JSON payload matching the LoopX contract
The contract requires classification, recommended_action, and optional run_output/run_error fields.
# adapters/ci_build_adapter.py
import json
import subprocess
from pathlib import Path
def main():
# 1. Load active state provided by LoopX
state_path = Path(".codex/goals/my-goal/ACTIVE_GOAL_STATE.md")
goal_state = state_path.read_text()
# 2. Execute external CI system
result = subprocess.run(
["ci-runner", "--job", "build"],
capture_output=True,
text=True
)
# 3. Build LoopX read-back payload
payload = {
"classification": "ci-build",
"recommended_action": "continue" if result.returncode == 0 else "block",
"run_output": result.stdout,
"run_error": result.stderr,
}
print(json.dumps(payload))
if __name__ == "__main__":
main()
This skeleton appears in docs/integration.md lines 19–34. The key insight: adapters never write state directly—they only return payloads for the kernel to ingest.
Step 4: Register the Adapter in LoopX
Update your project registry to bind goals to adapters. The CLI helper writes the necessary fields automatically:
loopx configure-goal \
--goal-id my-goal \
--adapter-kind ci_build_adapter_v0 \
--adapter-status connected
This modifies .loopx/registry.json to associate my-goal with your adapter implementation.
Step 5: Invoke Adapters Through the LoopX Runtime
All supported runtimes—Codex App, Codex CLI, Claude Code, or custom worker bridges—use the same tick sequence:
# Guard check: verify quota and gate status
loopx quota should-run --goal-id my-goal
# Claim ownership of this todo execution
loopx todo claim --goal-id my-goal
# Run the registered adapter
loopx todo update --goal-id my-goal --adapter adapters/ci_build_adapter.py
# Ingest read-back payload and update state
loopx refresh-state --goal-id my-goal
This sequence is documented in the README lines 37–44. The loopx/runtime.py module implements each command: quota should-run enforces rate limits, todo claim prevents concurrent execution, and refresh-state merges adapter output into durable state.
Step 6: Publish Projections to External UIs (Optional)
To surface results in dashboards, Lark Kanban boards, or other UIs, implement a projection sink. Sinks consume the compact run-index from refresh-state and render only public-safe fields.
Example from the Lark integration: loopx/extensions/lark/presentation/message_card.py builds Feishu reply cards without exposing internal identifiers. Private fields must be redacted—projection sinks are strictly read-only consumers.
For sink design patterns, see the Projection Sink Design section in the Agent Instructions.
Adapter Pattern for Chat Bots: Lark Integration
The loopx/extensions/lark/ directory demonstrates a complete provider integration. The Lark adapter:
- Implements the capability contract in
loopx/capabilities/ - Normalizes bot message formats to LoopX transitions
- Uses
message_card.pyfor UI separation
Reference: docs/integrations/lark-kanban-control-plane-adapter.md
Embedding LoopX in Custom Runners
For bespoke tooling beyond standard adapters, see docs/guides/custom-agent-runner-integration.md. This tutorial covers:
- Initializing the kernel programmatically
- Implementing custom tick loops
- Handling adapter failures with LoopX fallback semantics
This path is useful when you need deeper integration than shell commands provide.
Summary
- Install once, share everywhere: Use
scripts/install-local.shto set up a global LoopX base - Connect with
loopx bootstrap: Idempotent project setup creates registry and goal state files - Adapters are thin contracts: Read state, call external tools, return JSON payloads—never write state directly
- Standard tick sequence:
quota should-run→todo claim→todo update→refresh-state - Projection sinks for UIs: Consume run-index output, render public-safe fields, redact identifiers
Frequently Asked Questions
What programming languages can I use for LoopX adapters?
LoopX adapters can be written in any language. The kernel invokes them as subprocesses and expects JSON on stdout. The examples use Python for readability, but shell scripts, Go binaries, or Node.js programs work equally well as long as they read .codex/goals/<goal-id>/ACTIVE_GOAL_STATE.md and output the standard contract fields.
How does LoopX prevent concurrent adapter execution?
The loopx todo claim command acquires a distributed lock through the kernel's state management. If another process has already claimed the todo, the command fails fast with a clear error. This is implemented in loopx/runtime.py as part of the quota and todo command suite.
Can I use LoopX without Codex or Claude Code?
Yes. The docs/guides/custom-agent-runner-integration.md tutorial explains how to embed the kernel directly in your own runner. The CLI commands are convenience wrappers around loopx/runtime.py functions that you can import and call programmatically.
What happens if my adapter crashes or returns invalid JSON?
LoopX treats adapter failures as blocking events by default. The recommended_action falls back to "block", and the error output is captured in evidence logs. You can inspect failures with loopx status and retry manually, or implement automatic retry policies in your custom runner integration.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →