ipyai

A terminal IPython extension that adds Claude Agent SDK powered prompting

View the Project on GitHub AnswerDotAI/ipyai

DEV

Setup

Editable install:

pip install -e ipyai

Run tests:

cd ipyai
./tools/test.sh

Capture fresh Claude SDK shape samples:

cd ipyai
./tools/capture_samples.sh

The wrappers intentionally keep setup small:

File Map

CLI Flag Plumbing

ipyai uses ipythonng.cli.parse_flags() to split CLI args into ipyai flags and IPython args. parse_flags scans sys.argv[1:] for short flags (e.g. -b, -r, -l) that are not IPython’s own short flags, collects them and their values into IPYTHONNG_FLAGS env var, and passes the rest through to IPython. When the ipyai extension loads, _parse_ng_flags() in core.py reads IPYTHONNG_FLAGS and parses it with argparse. This two-stage approach lets ipyai flags coexist with IPython flags on the same command line (e.g. ipyai -b codex -r 5 --pdb).

Current Architecture

Prompt Flow

  1. Input starting with . is rewritten into %ipyai.
  2. IPyAIExtension.run_prompt() reconstructs recent code/output/note context from IPython history.
  3. Variable refs like $nameand shell refs like `!`cmd are injected above the prompt.
  4. The selected backend streams the turn:
    • core.py first builds a typed ConversationSeed
    • each backend then prepare_turn(...)s using that seed
    • Claude Agent SDK resumes or synthesizes a provider session
    • Claude API rebuilds flat history from the typed seed
    • Codex resumes or bootstraps an app-server thread from the typed seed
  5. astream_to_stdout() renders the response through Rich in TTY mode and stores the final transcript text locally.

Completion policy is shared in BaseBackend.complete():

Backends can still override complete() if a provider genuinely requires it, but the default path is now the contract.

State Model

There are two layers of state:

ipyai uses:

If prompt history exists locally but provider_session_id is missing, provider bootstrap is backend-specific:

Notebook save/load is explicit only:

There is no implicit startup.ipynb behavior.

Tools

The custom tool story is intentionally small:

pyrun does not call back into InteractiveShell.run_cell*. It delegates to safepyrun, looked up in shell.user_ns, matching the old ipycodex direct-call boundary and avoiding nested IPython cell execution.

Provider-specific tool exposure now fans out from the shared ToolRegistry:

The ipyai CLI loads safepyrun before ipyai, so normal terminal sessions get pyrun automatically. ipyai seeds the other custom tools into shell.user_ns directly.

Skills

Skills are Claude-native:

Samples

The samples/ directory exists so stream-shape spelunking does not need to be repeated.

Artifacts currently committed:

Those captures are useful when working on:

samples/toolslm_sdk_tool_demo.py is a minimal reference for the toolslm.get_schema_nm(...) -> claude_agent_sdk.tool(...) -> create_sdk_mcp_server(...) path.

Tests

The test suite is intentionally small and integration-heavy.

Current coverage focuses on:

Notes