Skip to main content

Brain layer for Kagura harnesses — headless CLI coding-agent launcher (claude -p today), subscription-auth hygiene, verdict, doctor primitives

Project description

kagura-brain

The provider-neutral "brain" layer shared by Kagura's CLI-brain harnesses (kagura-engineer, kagura-planner, kagura-code-reviewer).

These tools run a headless CLI coding agent as their brain. They were each re-implementing the same seams: launching the agent, stripping stale provider credentials so subscription auth wins, parsing exit codes and sentinel markers, and normalizing output. This package centralizes those seams.

Two adapters ship today — Claude Code (claude -p) and Codex CLI (codex exec) — as thin siblings over one shared launcher core (core._run + verdict + extract_block). Each strips its provider's credential/endpoint overrides from the child env so the CLI's subscription login wins: claude deny-sets ANTHROPIC_*; codex prefix-scrubs OPENAI_*/CODEX_* (including OPENAI_BASE_URL and CODEX_HOME).

from kagura_brain import claude, codex

claude.invoke("…prompt…", mcp_config=".mcp.json")   # claude -p
codex.invoke("…prompt…", sandbox="read-only")       # codex exec

MCP / approval differs by provider. Claude takes per-call --mcp-config / --allowedTools (see claude.mcp_args). Codex manages MCP servers persistently via codex mcp / ~/.codex/config.toml (no per-call flag), and its sandbox / approval is opt-in: pass sandbox= (read-only | workspace-write | danger-full-access) or bypass_approvals=True — neither is loosened by default.

BYO endpoint (opt-in)

By default both adapters strip the provider's endpoint/credential env so the subscription login wins. To deliberately route at a caller-chosen endpoint (Ollama Cloud / any compatible gateway), pass endpoint + api_key together — they are injected after the scrub, so only these explicit values reach the child while an ambient *_BASE_URL override stays stripped (#2):

# Codex → Ollama Cloud (OpenAI-compatible). "ollama-cloud" is an alias for
# codex.OLLAMA_CLOUD_ENDPOINT ("https://ollama.com/v1").
codex.invoke("…prompt…", endpoint="ollama-cloud", api_key="…")
# Codex → a LOCAL ollama/lmstudio backend (no endpoint/key needed):
codex.invoke("…prompt…", local_provider="ollama")
# Claude → a caller-supplied Anthropic-compatible gateway (no Ollama preset:
# Ollama Cloud is OpenAI-, not Anthropic-, compatible):
claude.invoke("…prompt…", endpoint="https://my-gateway/v1", api_key="…")

Supplying only one of endpoint/api_key raises ValueError; a non-https endpoint emits a UserWarning (prompt + code context goes off-box). With none of these set, the default subscription-auth path is byte-for-byte unchanged.

Provider-neutral selector

When a consumer supports more than one backend, select confines the claude/codex dispatch — and the per-provider MCP wiring — to the library, so each consumer no longer re-encodes it (#14):

import os

from kagura_brain import select, BRAIN_API_KEY_ENV

# "claude" (default) and "codex" are both supports_mcp=True.
handle = select(cfg.backend, endpoint=cfg.endpoint, api_key=os.environ.get(BRAIN_API_KEY_ENV))
handle.invoke("…prompt…", cwd=repo, mcp_config=".mcp.json", allowed_tools=MEMORY_TOOLS)
# Same mcp_config/allowed_tools to both; the adapter owns the mechanism:
# claude → --mcp-config/--allowedTools per call; codex → translates the .mcp.json
# into -c mcp_servers.* overrides and ignores allowed_tools (no codex analog).
# endpoint/api_key forward to both.

select takes primitives, never a consumer's Config, and never reads the env itself — the library owns only the standard name BRAIN_API_KEY_ENV ("KAGURA_BRAIN_API_KEY"); the consumer reads it and passes api_key= in. An unknown backend raises ValueError.

Why a separate package (not folded into the memory SDK)

Harness-support code splits cleanly along two axes:

Axis Belongs in Examples
memory kagura-memory-python-sdk sync client facade, .mcp.json setup, auth resolution, recall
brain this package CLI-agent launcher (claude -p + codex exec), subscription-auth hygiene, verdict contract, doctor primitives

Pushing CLI-agent spawning into a memory SDK would invert the layers ("memory spawns the agent"). So the brain axis lives here, and this package depends on no memory package — the two support libs are mutually independent.

kagura-engineer   kagura-planner   kagura-code-reviewer
        \                |                /
         `--> kagura-brain  +  kagura-memory-python-sdk <--'
                  (brain axis)            (memory axis)

Install

pip install kagura-brain
# or: uv add kagura-brain

Requires Python 3.11+. It has no Python runtime dependencies (stdlib-only) — and by design depends on no memory package (see the axis split above).

Prerequisites: the provider CLIs

kagura-brain is a launcher — it drives the provider CLIs as subprocesses, so each adapter needs its own CLI installed and on PATH. These are external tools, not pip dependencies; install only the one(s) you use:

Adapter Needs Auth (default path)
claude.invoke() Claude Code CLI (claude) — see docs signed in to your Claude subscription (the adapter strips ANTHROPIC_* so the subscription login wins)
codex.invoke() Codex CLI (codex) — see docs codex login (ChatGPT subscription; the adapter strips OPENAI_*/CODEX_*). Verified against Codex 0.133.0 (codex._CODEX_VERIFIED_VERSION)

The CLI binary is required even in BYO-endpoint mode — only the auth source changes: instead of the subscription login, the caller-supplied endpoint + api_key (or, for Codex, a local --oss --local-provider backend) are used. No subscription login is needed for the BYO path, but claude / codex must still be installed.

doctor primitives to check CLI launchability are planned (see Status).

Status

Public surface is built incrementally under TDD, one consumer migration per PR:

  • core — shared seam: BrainResult, _run (subprocess + env-scrub + timeout + utf-8 decode), as_text, extract_block
  • claude.invoke() — headless claude -p launcher (ANTHROPIC_*/CLAUDE_* deny-set, ---guarded prompt, mcp_args, opt-in BYO endpoint/api_key)
  • codex.invoke() — headless codex exec launcher (OPENAI_*/CODEX_* prefix scrub, ---guarded prompt, opt-in sandbox, BYO endpoint/api_key + local_provider)
  • verdictPROCEED set + exit-code map (contract only); see the exit-code contract for the canonical gate vocabulary vs reviewer-internal codes
  • doctor — provider-neutral check primitives (check_binary, check_auth, check_endpoint, aggregate) + presence-only claude.check()/codex.check() wrappers
  • select — provider-neutral BrainHandle selector over the adapters (supports_mcp capability; per-provider MCP wiring confined to the library — claude per-call flags, codex -c mcp_servers.*; BRAIN_API_KEY_ENV name)

Development

uv sync --extra dev
uv run pytest          # tests
uv run ruff check .    # lint
uv run ruff format .   # format
uv run mypy            # type check

See CONTRIBUTING.md for the full workflow and CHANGELOG.md for release history.

License

Apache-2.0. See LICENSE and NOTICE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kagura_brain-0.5.0.tar.gz (88.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kagura_brain-0.5.0-py3-none-any.whl (34.2 kB view details)

Uploaded Python 3

File details

Details for the file kagura_brain-0.5.0.tar.gz.

File metadata

  • Download URL: kagura_brain-0.5.0.tar.gz
  • Upload date:
  • Size: 88.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for kagura_brain-0.5.0.tar.gz
Algorithm Hash digest
SHA256 423850754140e61dc0fd12dc55b9242532b741f7224d9c52cd5840aed869e95f
MD5 15da7126280eede39c2a3bb82fc1e934
BLAKE2b-256 6909e9a08a759f4d4993e6e7ce1ae2ae44e2dc48b4a274652657aa54c1d12543

See more details on using hashes here.

Provenance

The following attestation bundles were made for kagura_brain-0.5.0.tar.gz:

Publisher: publish.yml on kagura-ai/kagura-brain

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kagura_brain-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: kagura_brain-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 34.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for kagura_brain-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9de803193641e15d66b0177bec6176b78b15771fd14648295fcc8d097d9a5a8a
MD5 676184f4b71af0508e48180a6ee4d618
BLAKE2b-256 85cb172aa4d2ed3fc2ae8bb7946f378e94a796d234ace78c50862d51a6fb145c

See more details on using hashes here.

Provenance

The following attestation bundles were made for kagura_brain-0.5.0-py3-none-any.whl:

Publisher: publish.yml on kagura-ai/kagura-brain

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page