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 "codex has no per-call MCP" rule — 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) → supports_mcp=True; "codex" → supports_mcp=False.
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)
# claude → forwards mcp_config/allowed_tools; codex → drops them (logs once),
# since codex wires MCP out-of-band. 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)
  • 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, codex MCP-drop confined to the library, 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.3.0.tar.gz (75.0 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.3.0-py3-none-any.whl (28.6 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: kagura_brain-0.3.0.tar.gz
  • Upload date:
  • Size: 75.0 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.3.0.tar.gz
Algorithm Hash digest
SHA256 64bfc84c1f3e6ab42f9fc65fdc0c05e4674b5fe013273d58592337a4bf20883e
MD5 e589bb27ff234450edb4535af49fb410
BLAKE2b-256 4c08a36dc7626b36d857b3bd464915d11285ca8dd4a7e876b3fbab57c6c45c37

See more details on using hashes here.

Provenance

The following attestation bundles were made for kagura_brain-0.3.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.3.0-py3-none-any.whl.

File metadata

  • Download URL: kagura_brain-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 28.6 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.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d900ce37a21e41c60fa6dc2fac95efb88126b2ea3bac9f52ccea47a0e5e62b0d
MD5 53328a14dd25bd3b22b98ff68e804035
BLAKE2b-256 4f07a88c78980bcd11c784f29569969dc3d4daf75518129fd3199538b1d5002f

See more details on using hashes here.

Provenance

The following attestation bundles were made for kagura_brain-0.3.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