Catalog PyPI
PACKAGE EXPLORERView in registry

agenticore

PyPI

Claude Code runner and orchestrator — thin job lifecycle, repo management, and OTEL pipeline

Versions collected1
Direct dependencies14From release 1.9.0
Last observed20 Oct, 22:18 UTC

README

Version 1.9.0 documentation

Agenticore

Two modes, one binary. Run a fleet of Claude Code agents that clone repos and ship PRs — or expose any customized Claude Code agent as a real-time, OpenAI-compatible chat completion endpoint with token-by-token thinking and tool deltas. Flip between modes with one environment variable.

License: MIT Tests Docker Helm PyPI Python 3.12+

                          ┌─── AGENT_MODE=false (default) ────────────┐
                          │  FLEET MODE — Orchestrator                 │
                          │  Submit a task, get a PR                   │
                          │                                            │
   MCP / REST / CLI ─────►│  clone repo ──► bespoke worktree           │
                          │       │              │                     │
                          │       └──► claude -p "<task>" ──► auto-PR  │
                          │                              └──► OTEL     │
                          │  KEDA-scaled fleet • work-stealing queue   │
   ┌─────────────┐        └────────────────────────────────────────────┘
   │ agenticore  │
   │   binary    │
   └─────────────┘        ┌─── AGENT_MODE=true ────────────────────────┐
                          │  AGENT MODE — Customized agent endpoint    │
                          │  Drop-in OpenAI chat completion server     │
                          │                                            │
   OpenAI-compatible ────►│  load agent package (system prompt, MCP    │
   chat clients           │    servers, hooks, skills, identity)       │
   (LibreChat,            │                                            │
    OpenWebUI,            │  POST /v1/chat/completions stream=true     │
    LiteLLM,              │       │                                    │
    custom UI,            │       └─► live SSE deltas:                 │
    raw curl -N)          │            thinking_delta (token-by-token) │
                          │            tool_use + tool_result          │
                          │            assistant text                  │
                          │                                            │
                          │  Sticky slash toggles per agent            │
                          │  Fully auditable — wire/disk/Redis layers  │
                          └────────────────────────────────────────────┘

Pick a mode

Fleet mode (default)Agent mode (AGENT_MODE=true)
What it doesAccepts coding tasks, clones repos, runs Claude Code in bespoke worktrees, opens PRsLoads a pre-configured Claude Code agent package and exposes it as a chat completion endpoint
API surface/jobs REST · run_task MCP tool · agenticore run CLI/v1/chat/completions — fully OpenAI-compatible, streaming and non-streaming
LifecyclePer-job clone + worktree, discarded after PRLong-lived agent identity loaded once at container startup
ScalingKEDA on Redis queue depth — N pods steal jobs from one queueOne StatefulSet per agent identity; scale horizontally per agent
OutputA pull request, an OTEL trace, a job result in RedisLive SSE deltas as chat.completion.chunk JSON, full transcript on disk
Drop-in forCI/CD pipelines, MCP-aware editors, internal "fix this" botsLibreChat, OpenWebUI, LiteLLM model routing, any OpenAI SDK client
Best for"We use Claude Code to refactor / fix / generate PRs across many repos""We want our chat clients to talk to a customized Claude agent over the OpenAI protocol"

Both modes share the same binary, the same Docker image, the same Helm chart, the same profile system, the same Redis+file fallback, and the same OTEL trace pipeline. You don't pick at install time. You pick at runtime with one environment variable.


Why agenticore

You have Claude Code. You want it to do work for you programmatically. You have two shapes the work tends to take:

  1. Headless coding tasks across repos — "fix the auth bug", "add tests for the parser", "refactor this module". You want a fleet that accepts these, clones the right repo, runs Claude in a clean worktree, and opens a PR. → Fleet mode.

  2. A customized Claude agent your other tools can talk to — a personal assistant, a domain expert, a finops bot, a docs writer — exposed as an OpenAI-compatible endpoint so LibreChat, OpenWebUI, your LiteLLM router, or any OpenAI SDK client can drop it in as a "model". With real-time streaming of the agent's thinking, tool calls, and answers — not buffered, not batched, not faked. → Agent mode.

Agenticore is one binary that does both. Profiles, hooks, MCP whitelists, Redis state, OTEL traces, Helm chart — all shared between the two modes. Your operations team learns one thing.


🟦 FLEET MODE

Submit a task, get a PR. The original positioning.

MCP Client / REST Client / CLI
            │
            ▼
    ┌── Agenticore (Fleet Mode) ─────────────────────────────────┐
    │   Auth · Router · Job Queue                                │
    │                                                            │
    │   Clone repo ──► Bespoke worktree ──► claude -p "task"     │
    │   (cached)       (locked branch)      (cwd = worktree)     │
    │                                         │                  │
    │                                         ▼                  │
    │                                   Auto-PR (gh)             │
    │                                   Job result → Redis       │
    └──────────────────────┬─────────────────────────────────────┘
                           │
                    OTEL Collector
                    → Langfuse / PostgreSQL
  • Accepts tasks from MCP clients, REST, or CLI — same API surface, one port
  • Clones and caches repos, serializes concurrent access with distributed locks
  • Creates bespoke worktrees — locked before Claude starts, deterministic branch names
  • Applies execution profiles — installed into ~/.claude/ at startup via agentihooks
  • Spawns claude -p "<task>" in the worktree and opens a PR when it succeeds
  • Ships full OTEL traces (prompts, tool calls, token counts) to Langfuse / PostgreSQL
  • KEDA autoscaling on Redis queue depth + graceful drain on pod shutdown

Quickstart

# Set credentials
export ANTHROPIC_AUTH_TOKEN=sk-ant-...
export GITHUB_TOKEN=ghp_...

# Start the server
agenticore serve

# Submit a task and wait for the PR URL
agenticore run "fix the null pointer in auth.py" \
  --repo https://github.com/org/repo \
  --wait

REST

# Submit a job (async — returns immediately with job ID)
curl -X POST http://localhost:8200/jobs \
  -H "Content-Type: application/json" \
  -d '{"task":"fix the auth bug","repo_url":"https://github.com/org/repo"}'

# Submit and wait
curl -X POST http://localhost:8200/jobs \
  -H "Content-Type: application/json" \
  -d '{"task":"fix the auth bug","repo_url":"https://github.com/org/repo","wait":true}'

# Inspect
curl http://localhost:8200/jobs/{job_id}
curl "http://localhost:8200/jobs?limit=10&status=running"
curl -X DELETE http://localhost:8200/jobs/{job_id}

MCP tools (fleet mode)

ToolDescription
run_taskSubmit a task for Claude Code execution
get_jobGet status, output, and PR URL for a job
list_jobsList recent jobs
cancel_jobCancel a running or queued job
list_profilesList available execution profiles
plan_taskCreate a read-only implementation plan
execute_planExecute a ready plan as a coding job
list_worktreesList all worktrees with age, size, branch, push status
cleanup_worktreesRemove specific worktrees (unlock + delete)

Connect any MCP client at http://localhost:8200/mcp (Streamable HTTP) or /sse (legacy SSE).


🟩 AGENT MODE

One environment variable. Now you have a customized Claude agent talking the OpenAI protocol with real-time thinking + tool streaming.

        AGENT_MODE=true + AGENT_MODE_PACKAGE_DIR=./my-agent-package
                                        │
                                        ▼
  ┌── Agenticore (Agent Mode) ──────────────────────────────────────┐
  │                                                                 │
  │   Load package once at startup:                                 │
  │     ├─ system.md (identity, instructions)                       │
  │     ├─ .claude/ (settings, hooks, skills, agents)               │
  │     └─ .mcp.json (tool servers this agent can call)             │
  │                                                                 │
  │   POST /v1/chat/completions stream=true                         │
  │     │                                                           │
  │     ├─ strip slash tokens (server-side, deterministic)          │
  │     ├─ load sticky visibility config from Redis                 │
  │     ├─ spawn claude --output-format stream-json                 │
  │     │                  --include-partial-messages               │
  │     ├─ read claude stdout line-by-line                          │
  │     │     thinking_delta  → delta.reasoning_content (live)      │
  │     │     text_delta      → delta.content (live)                │
  │     │     tool_use_block  → ```tool_use:NAME fenced block       │
  │     │     tool_result     → ```tool_result fenced block         │
  │     └─ flush each chunk to the open HTTP connection             │
  │                                                                 │
  └─────────────────────────────────────────────────────────────────┘

Drop-in for any OpenAI-compatible client. Because the endpoint speaks /v1/chat/completions and emits standard chat.completion.chunk JSON over SSE, you can register an agenticore-backed agent as an "OpenAI custom model" inside:

  • LibreChat — add as a custom OpenAI endpoint, pick from the model dropdown
  • OpenWebUI — same pattern
  • LiteLLM — register as openai/<agent> with api_base=http://<agent>:8200/v1, then route any LiteLLM client at it
  • OpenAI SDK (Python, JS, Go, Rust) — OpenAI(base_url="http://<agent>:8200/v1") and call chat.completions.create(...) exactly like you would against api.openai.com
  • curl -N — raw SSE works fine

Killer features

  • Real-time SSE streaming, fully auditable, fully traceable. Thinking blocks stream token-by-token as the model generates them. Tool calls and results stream live as the agent invokes them. Assistant text streams progressively. Nothing is buffered to the end of the turn. The streaming hot path reads claude's stdout directly via --output-format stream-json --verbose --include-partial-messages — no transcript polling, no Redis indirection, no JSONL flush race.
  • Thinking renders in delta.reasoning_content — separate reasoning panel in reasoning-aware clients (LibreChat, OpenWebUI), with x_agenticore_event_type="thinking" for custom clients that want explicit tagging.
  • Tool calls render as fenced markdown blocks — ```tool_use:NAME paired with ```tool_result below it. Deliberately not OpenAI's delta.tool_calls schema, which would make chat clients try to client-execute the tool and fail with "Tool not found".
  • Sticky per-agent visibility toggles intercepted server-side, before claude ever sees the prompt:
    • /show-thinking / /hide-thinking
    • /show-tools / /hide-tools
    • /show-all / /hide-all
    • /stream-status (returns the current config inline as a meta SSE event)
  • Multi-turn aware — toggle detection runs against the last user message, not the flattened history, so slash commands work on turn 2+. Toggle-only requests (e.g. just /show-all) return inline status without spawning claude — zero token cost.
  • Three-layer observation — every visible event reaches (1) the client over the wire, (2) claude's transcript JSONL on disk, and (3) optionally the Redis bus (non-streaming path) for cross-process subscribers. Cross-validate all three with tests/smoke/verify_streaming_pipeline.sh <agent>.
  • Async completion queue for fire-and-forget — wait=false pushes to Redis, a worker picks it up, poll GET /completions/{uuid}.
  • Session continuity — resume a conversation across requests via the external correlation UUID.
  • Redis+file fallback — works without Redis (inline execution, file-based state).

Quickstart

# Start the server in agent mode pointing at your agent package
AGENT_MODE=true \
AGENT_MODE_PACKAGE_DIR=./my-agent-package \
AGENTICORE_TRANSPORT=sse \
agenticore serve

# Toggle visibility once (sticky per agent — persists in Redis)
curl -sN http://localhost:8200/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{"model":"sonnet","stream":true,"messages":[{"role":"user","content":"/show-all"}]}'

# Now have a real conversation — watch thinking tokens + tool calls stream live
curl -sN http://localhost:8200/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{"model":"sonnet","stream":true,"messages":[
        {"role":"user","content":"is 17077 prime? think hard, then list any files in /tmp"}
      ]}'

# Non-streaming JSON (no slash tokens needed)
curl -X POST http://localhost:8200/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{"model":"sonnet","messages":[{"role":"user","content":"hello"}]}'

Drop into LibreChat

# librechat.yaml
endpoints:
  custom:
    - name: "Agenticore Agents"
      apiKey: "${LITELLM_API_KEY}"
      baseURL: "http://litellm.your-cluster.svc:4000/v1"
      models:
        fetch: true
      titleConvo: true

Register the agent in LiteLLM as a model pointing at the agenticore pod:

# Via LiteLLM admin (or the litellm_tools MCP)
model_name: my-agent
litellm_params:
  model: openai/my-agent
  api_base: http://my-agent.namespace.svc:8200/v1

Now my-agent shows up in LibreChat's model picker. Token-by-token thinking renders in the reasoning panel. Tool calls stream live as fenced markdown blocks.

Drop into the OpenAI SDK

from openai import OpenAI

client = OpenAI(base_url="http://my-agent.namespace.svc:8200/v1", api_key="n/a")

stream = client.chat.completions.create(
    model="sonnet",
    stream=True,
    messages=[
        {"role": "user", "content": "/show-all explain how an OS scheduler works step by step"},
    ],
)
for chunk in stream:
    delta = chunk.choices[0].delta
    if reasoning := getattr(delta, "reasoning_content", None) or delta.model_dump().get("reasoning_content"):
        print(f"[think] {reasoning}", end="", flush=True)
    elif delta.content:
        print(delta.content, end="", flush=True)

Full reference: SSE Streaming docs · Self-test walkthrough · Agent Mode architecture


Shared infrastructure (both modes)

Everything below applies to both Fleet mode and Agent mode. Same Docker image, same Helm chart, same env vars, same Redis schema.

Install

pip install agenticore

Or from source:

git clone https://github.com/The-Cloud-Clockwork/agenticore.git
cd agenticore
pip install -e .

Profiles

Profiles are directory packages that configure how Claude Code runs. Each profile is a self-contained .claude/ tree installed into ~/.claude/ at container startup by agentihooks global. Claude Code reads from ~/.claude/ by default.

<profiles-dir>/{name}/
├── profile.yml          ← Agenticore metadata (model, turns, auto_pr, timeout…)
├── .claude/
│   ├── settings.json    ← Hooks, tool permissions, env vars
│   ├── CLAUDE.md        ← System instructions for Claude
│   ├── agents/          ← Custom subagents
│   └── skills/          ← Custom slash-command skills
└── .mcp.json            ← MCP server config merged into the job

Profiles support inheritance via extends: and ship with the agentihooks PyPI package (a pip dependency of agenticore). Personal overrides live in ~/.agenticore/profiles/; set AGENTICORE_AGENTIHOOKS_URL to clone a fork (or bind-mount your local checkout at <SHARED_FS_ROOT>/agentihooks) for editable-install dev loopback. Full reference: Profile System docs.

Helm (Kubernetes)

Production-ready Helm chart published to GHCR. Deploys a StatefulSet with a shared RWX PVC (NFS / EFS / Azure Files / Ceph) so all pods share the same repo cache and job state, with KEDA autoscaling on Redis queue depth and graceful drain on pod shutdown.

Internet ──► LoadBalancer :8200
                    │
     ┌──────────────▼──────────────────────────┐
     │  Agenticore StatefulSet (0..N pods)     │
     │  Work-stealing from Redis queue         │
     └──────────┬──────────────────────────────┘
                │                │
         ┌──────▼───────┐  ┌─────▼───────────┐
         │  Redis       │  │  Shared RWX PVC │
         │  jobs · locks│  │  /shared/       │
         │  KEDA queue  │  │  ├─ repos/      │
         └──────────────┘  │  ├─ jobs/       │
                           │  └─ job-state/  │
         KEDA ScaledObject └─────────────────┘
         watches Redis queue
# Create the secret
kubectl create secret generic agenticore-secrets \
  --from-literal=redis-url="redis://:password@redis:6379" \
  --from-literal=anthropic-api-key="sk-ant-..." \
  --from-literal=github-token="ghp_..."

# Install (fleet mode)
helm install agenticore \
  oci://ghcr.io/the-cloud-clockwork/charts/agenticore \
  --set storage.className=your-rwx-storage-class

# Install (agent mode)
helm install my-agent \
  oci://ghcr.io/the-cloud-clockwork/charts/agenticore \
  --set storage.className=your-rwx-storage-class \
  --set agentMode.enabled=true \
  --set agentMode.agentName=my-agent

Full Kubernetes guide: Kubernetes Deployment.

Docker

# Local dev — full stack (Agenticore + Redis + PostgreSQL + OTEL Collector)
cp .env.example .env
docker compose up --build -d

# Production (fleet mode) — Agenticore only
docker run -d -p 8200:8200 \
  -e AGENTICORE_TRANSPORT=sse \
  -e ANTHROPIC_AUTH_TOKEN=sk-ant-... \
  -e REDIS_URL=redis://your-redis:6379/0 \
  -e GITHUB_TOKEN=ghp_... \
  ghcr.io/the-cloud-clockwork/agenticore

# Production (agent mode)
docker run -d -p 8200:8200 \
  -e AGENT_MODE=true \
  -e AGENTIHUB_AGENT=my-agent \
  -e AGENTICORE_TRANSPORT=sse \
  -e ANTHROPIC_AUTH_TOKEN=sk-ant-... \
  -e REDIS_URL=redis://your-redis:6379/0 \
  ghcr.io/the-cloud-clockwork/agenticore

Authentication

Authentication is optional. When disabled, all endpoints are public.

# API keys — comma-separated for multiple
AGENTICORE_API_KEYS="key-1,key-2" agenticore serve

Pass the key via X-Api-Key header, ?api_key=... query param, or Authorization: Bearer .... The /health endpoint is always public.

Claude credentials resolved in order: CLAUDE_CODE_OAUTH_TOKEN → ANTHROPIC_AUTH_TOKEN + ANTHROPIC_BASE_URL. GitHub credentials: GitHub App (GITHUB_APP_ID + key + installation ID) → static GITHUB_TOKEN → none (public repos only).

OTEL Observability

Every job (fleet mode) and every completion (agent mode) produces a Langfuse trace with spans for each Claude turn including prompts, tool calls, and token counts.

LANGFUSE_PUBLIC_KEY=pk-lf-...
LANGFUSE_SECRET_KEY=sk-lf-...
LANGFUSE_HOST=https://cloud.langfuse.com
AGENTICORE_OTEL_ENABLED=true
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317

The bundled docker-compose.yml includes an OTEL Collector pre-wired to push traces to Langfuse and PostgreSQL. Full setup: OTEL Pipeline docs.

Key environment variables

VariableDefaultDescription
AGENT_MODEfalseThe mode switch. true enables agent mode
AGENT_MODE_PACKAGE_DIR(empty)Path to the agent package (agent mode only)
AGENTIHUB_AGENT(empty)Agent name to load from agentihub (agent mode)
AGENTICORE_TRANSPORTstdiosse for HTTP server, stdio for MCP pipe
AGENTICORE_HOST127.0.0.1Bind address
AGENTICORE_PORT8200Server port
AGENTICORE_API_KEYS(empty)Comma-separated API keys (optional)
ANTHROPIC_AUTH_TOKEN(empty)Anthropic API key (or use CLAUDE_CODE_OAUTH_TOKEN)
REDIS_URL(empty)Redis URL — omit for file-based fallback
GITHUB_TOKEN(empty)GitHub token for auto-PR (fleet mode)
AGENTIHOOKS_PROFILEcodingActive profile (fleet mode)
AGENTICORE_CLAUDE_TIMEOUT3600Max claude runtime in seconds
AGENTICORE_AGENTIHOOKS_URL(empty)Clone ONCE to <SHARED_FS_ROOT>/<dir-from-url> + uv pip install -e. Default install is from PyPI.
AGENTICORE_AGENTIHOOKS_BUNDLE_URL(empty)Git URL to clone the bundle content repo (optional)
AGENTICORE_AGENTIHUB_URL(empty)Git URL for agentihub repo (required for agent mode)
AGENTIHUB_DIR(auto)Path to a local agentihub checkout — used by agenticore agents to find local agent packages. See below.
AGENTICORE_SHARED_FS_ROOT(empty)Base directory for all clones — /shared in k8s, $HOME locally

Pointing at AgentiHub

There are two separate ways agenticore reaches AgentiHub, and they use different variables. Mixing them up is the most common setup mistake:

You wantVariableWhat it is
The server/pod to provision an agent (agent mode)AGENTICORE_AGENTIHUB_URL + AGENTIHUB_AGENTA git URL to clone, plus which agent to load
The agenticore agents CLI to list local agent packagesAGENTIHUB_DIRA local directory path already on disk

Note the asymmetry: the URL is prefixed (AGENTICORE_AGENTIHUB_URL) but the agent name is not (AGENTIHUB_AGENT). A bare AGENTIHUB_URL is not read by anything.

AGENTIHUB_DIR points at the directory that contains agents/ — not at agents/ itself:

export AGENTIHUB_DIR=/path/to/agentihub     # contains agents/<name>/package/CLAUDE.md
agenticore agents

The CLI resolves it in this order, first hit wins:

  1. --agentihub-dir /path on the command line
  2. AGENTIHUB_DIR environment variable
  3. ~/.agenticore/state.json → {"agentihub": {"path": "..."}} — written by pressing c in the TUI
  4. Sibling-directory discovery — walks up looking for a neighbouring agentihub/agents/, so a standard ecosystem checkout works with nothing set

An agent is any directory containing agents/<name>/package/CLAUDE.md. Its description and capabilities are read from agents/<name>/package/command.yml.

Full reference: Configuration docs.

CLI commands

CommandDescription
agenticore serveStart the server (fleet or agent mode based on env)
agenticore run "<task>" --repo <url> [--wait]Submit a task (fleet mode)
agenticore jobs / agenticore job <id>List / inspect jobs
agenticore cancel <id>Cancel a running job
agenticore profilesList execution profiles
agenticore agentsInteractive TUI — local agent packages (add --k8s to include K8s pods)
agenticore agents --headless <action>Headless: list, chat, job, sync, health, local
agenticore hooks sync [--target T]Clone/fetch profile sources
agenticore agent --compose-upBring up the local dev stack
agenticore drainDrain pod before shutdown (Kubernetes)
agenticore status / version / updateServer health, version, self-update

Full CLI reference: CLI Commands.


Documentation

Get started

Architecture

Deployment

Reference


Development

pip install -e ".[dev]"

# Tests
pytest tests/unit -v -m unit --cov=agenticore

# Lint
ruff check agenticore/ tests/
ruff format --check agenticore/ tests/

agentihooks dev loopback

agentihooks ships as a PyPI dependency of agenticore (agentihooks>=1.8.0 in pyproject.toml) and is pulled transitively when you pip install agenticore or build the Docker image. You do not need to clone it to get a working runtime. A pod restart is the upgrade path — no periodic re-sync watcher.

When you're iterating on agentihooks itself, set AGENTICORE_AGENTIHOOKS_URL and let the runtime clone (or bind-mount the checkout at the same destination to skip the clone). Either way, uv pip install -e runs against the resolved path so edits to the source land live on the next Python import.

Env varBehaviour
AGENTICORE_AGENTIHOOKS_URL=<git url> (+ optional _BRANCH)At boot: clone ONCE to <SHARED_FS_ROOT>/<dir-from-url>, then uv pip install -e. A pre-mounted checkout at the same destination is trusted as-is (no fetch).
(unset)Container runs the PyPI-installed version. Default.

docker-compose.dev.yml wires the loopback by bind-mounting your local checkout at the URL-derived destination:

volumes:
  - /home/iamroot/dev/agentihooks:/shared/agentihooks
environment:
  AGENTICORE_SHARED_FS_ROOT: /shared
  AGENTICORE_AGENTIHOOKS_URL: https://github.com/your-org/agentihooks

Edit the mounted checkout → re-run the server (or let Python re-import on worker restart). All clone+watcher machinery is gone; bundle and agentihub refresh on-demand via agenticore hooks sync, POST /admin/sync, or pod restart. See docs/reference/configuration.md for full env-var semantics.

PRs welcome. The feat/* branches in the repo show recent work — the most recent landed feature is the token-by-token SSE streaming layer (feat/stream-json-direct → dev → main at f440e3c, released as v1.3.0).

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
1.9.023 Jul 202614

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
the-cloud-clockwork/agenticore

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 22:18 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:e7bc9c4dd308e5f0d35ad8da94705917ab409de8b0442af79616434c27df9e77