Guidance for Claude Code when working in this repository.
# Setup
uv venv --python 3.12 && source .venv/bin/activate
uv sync --extra dev # install with test deps
# Run anything through uv (never bare python/pytest)
uv run pytest # full suite (parallel, coverage)
uv run pytest tests/agents/base/ -v # specific directory
uv run pytest -m unit # by marker: unit, integration, slow, requires_ml
uv run pytest -k "test_human" # by name pattern
uv run python scripts/run_lit_agent.py- Python 3.12+ — use modern syntax everywhere:
str | NonenotOptional[str],list[str]notList[str]- Generic classes:
class Memory[T](BaseModel):notclass Memory(BaseModel, Generic[T]): type Alias = ...for type aliases where appropriate
- All async: agents and tools implement
async def _arun() - Pydantic v2 for all models
Human-centric Multi-Agent System (MAS) framework for scientific discovery.
See docs/design_philosophy.md for full design principles.
Everything inherits from AbstractBase. See docs/specs/AKD_BASE.md for the full reference.
Key exports from akd._base:
| Class / Protocol | Purpose |
|---|---|
AbstractBase |
Concrete base with schema validation, streaming, and config binding (agents, tools) |
InputSchema / OutputSchema / IOSchema |
Typed schemas with required docstrings |
BaseConfig |
Configuration base |
ConfigBindingMixin |
Opt-in: config property binding + metadata binding (already on AbstractBase) |
AKDExecutable / AKDTool / RunContextProtocol |
Structural protocols — framework adapters satisfy these without inheriting BaseAgent / BaseTool |
StreamEvent |
Streaming event hierarchy |
ToolCall / ToolResult |
Tool calling data models |
RunContext |
Execution context passed to agents (in _base/structures.py) |
HumanResponse |
Human reply for HITL resumption (in _base/structures.py) |
validate_input / validate_output |
Standalone schema validators for non-inheriting adapters |
Every agent/tool has 4 parts:
from akd._base import InputSchema, OutputSchema
from akd.agents._base import BaseAgent, BaseAgentConfig
class MyInput(InputSchema):
"""What goes in."""
query: str
class MyOutput(OutputSchema):
"""What comes out."""
answer: str
class MyConfig(BaseAgentConfig):
model: str = "gpt-4o-mini"
class MyAgent(BaseAgent[MyInput, MyOutput]):
config_schema = MyConfig
input_schema = MyInput
output_schema = MyOutput
async def _arun(self, params: MyInput, run_context: RunContext | None = None, **kwargs) -> MyOutput:
...Same pattern for tools — inherit BaseTool[InSchema, OutSchema] with BaseToolConfig.
Agents support streaming via astream() which yields typed StreamEvent subclasses.
The HumanTool enables HITL: the tool loop detects it via isinstance (not by name) and emits HumanInputRequiredEvent.
See specs:
docs/specs/STREAMING.md— event types, streaming mixindocs/specs/TOOL_CALLING.md— tool loop, ToolCall/ToolResult, HumanTool interceptiondocs/specs/HUMAN_INTERRUPT.md— pause/resume lifecycledocs/specs/AGENT_MEMORY.md— memory sessions, message management
akd/_base/structures.py (internal):
RunContext— execution context (messages, human_response, run_id, extra keys)HumanResponse— human's reply to HITL event (extends ToolResult)
akd/structures.py (public, also re-exports HumanResponse):
SearchResult/SearchResultItem— search results with metadataHumanResponse— re-exported for backend convenience
akd/
├── _base/ # Base classes, streaming, tool calling, memory, structures
├── agents/ # Agent implementations
│ ├── _base.py # BaseAgent, InstructorBaseAgent, LiteLLMInstructorBaseAgent
│ └── relevancy.py # RelevancyAgent, MultiRubricRelevancyAgent
├── tools/ # Tool implementations
│ ├── _base.py # BaseTool, BaseToolConfig
│ ├── human.py # HumanTool (HITL)
│ ├── search/ # SearxNG, Serper, SemanticScholar, Composite, Pipeline
│ ├── scrapers/ # Web, PDF, Crawl4AI, PyPaperBot, Docling scrapers
│ ├── resolvers/ # DOI, Arxiv, ADS, Unpaywall resolvers
│ ├── reranker.py # CrossEncoder, NoOp rerankers
│ ├── relevancy.py # Relevancy checker
│ └── source_validator.py
├── configs/ # Configuration (project, prompts, lit)
├── guardrails/ # Safety and validation guardrails
├── mapping/ # Runtime agent registry + field-mapping machinery
├── planner/ # Workflow planning (agents registered at runtime)
└── structures.py # Public data structures
tests/ # Mirrors akd/ structure — pytest + asyncio + xdist
docs/specs/ # Detailed specifications (see links above)
agent-stuff/ # Local-only (gitignored) plans and PR docs
Local-only directory (gitignored) for plans and PR docs.
agent-stuff/
├── plans/
│ ├── active/ # In-progress or upcoming plans
│ └── completed/ # Archived after implementation
└── prs/
├── open/ # Docs for open PRs
└── closed/ # Merged/closed PR docs
- Plan files: prefix with date —
YYYY-MM-DD-<descriptive-name>.md- Example:
2026-02-04-human-chat-flow.md
- Example:
- PR files: name by PR number —
<number>.md- Example:
335.md
- Example:
- When a plan is implemented, move it from
active/→completed/ - When a PR is merged/closed, move its doc from
open/→closed/