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.1.tar.gz (90.6 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.1-py3-none-any.whl (34.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: kagura_brain-0.5.1.tar.gz
  • Upload date:
  • Size: 90.6 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.1.tar.gz
Algorithm Hash digest
SHA256 b1cca73719797811254e961718aa02f8b353520435b898e612b8595ad1424667
MD5 bcf28bd947fed2de2de9fa6a0c072855
BLAKE2b-256 c7c8046b85471204f7cd45a6218876b86e4b47c7c841c326de047a9f3ab57c62

See more details on using hashes here.

Provenance

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

File metadata

  • Download URL: kagura_brain-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 34.7 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 9aa3305cb20173bec61311b8c2e058712b95d904cae69c7daa19c11f402e88aa
MD5 09120d8f04c0c6bf7dae794c076ff0b2
BLAKE2b-256 21c752e5b62a35b88dfe13b55fc5be9958fc5e413d0dbb8fd1f319ba60405f37

See more details on using hashes here.

Provenance

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