This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Don't build code to do what the LLM already does well. Give it context instead of building infrastructure.
| Principle | Meaning |
|---|---|
| LLM-First | Trust the model; don't over-engineer |
| Explicit Over Implicit | No magical defaults; 3 lines of clear code beats hidden behavior |
| Soft-Typed Events | event_type: String + data: JSON, not rigid enums |
| Graceful Unknowns | Unknown event types logged, not errors |
| Agent Isolation | Agents depend only on core, never on each other |
| Config at Construction | Agent-specific config in constructors, not shared context |
| Hermetic Implementations | Agent/tool/hook implementations live in files, not embedded in library code |
Corollary: Breaking changes are preferred over backwards-compatibility shims. Clean breaks, no deprecation warnings.
Hermetic Rule: Never embed agent definitions, tool configs, or hook logic as string constants in library code. Implementations must live in their own files:
- Rust agents →
agents/gemicro-{name}/ - Markdown agents →
agents/runtime-agents/{name}.md - Tools →
tools/gemicro-{name}/ - Hooks →
hooks/gemicro-{name}/
Gemicro is a CLI agent exploration platform for AI agent patterns, powered by Gemini API via genai-rs.
Architecture: 27-crate workspace (6 agents, 10 tools, 6 hooks, 5 core)
Status: Core complete. Remaining work in GitHub Issues.
make check # Format + clippy + tests (pre-push gate)
make fmt # Check formatting
make clippy # Clippy with -D warnings (uses test profile for cache sharing)
make test # Unit tests only (excludes doctests for speed)
make test-all # Full suite including integration tests (requires GEMINI_API_KEY)Don't run the full suite after every change. Target only the crates you modified:
cargo nextest run -p gemicro-core # Single crate (~30s)
cargo nextest run -p gemicro-core -p gemicro-runner # Multiple crates
cargo nextest run test_name # Single test by nameRun make check once before git push. CI catches cross-crate issues.
| Purpose | cargo test | cargo nextest |
|---|---|---|
| Include ignored | -- --include-ignored |
--run-ignored all |
| Single test | test_name |
test_name (or -E 'test(/regex/)') |
| Release mode | --release |
--cargo-profile release |
cargo run -p gemicro-deep-research-agent --example deep_researchexport GEMINI_API_KEY="your-api-key" # Required for integration tests
# Debug genai-rs HTTP traffic
LOUD_WIRE=1 cargo run -p gemicro-developer-agent --example developerFor tool execution debugging, use gemicro-audit-log (structured logging without HTTP noise).
gemicro-core (Agent, Tool, Interceptor traits, LLM client - GENERIC ONLY)
↓
tools/* (one crate per tool)
hooks/* (one crate per hook)
agents/* (one crate per agent - hermetic isolation)
↓
gemicro-runner (execution, metrics)
↓
gemicro-eval (datasets, scorers)
gemicro-cli (terminal UI)
| Crate | Contains | Does NOT Contain |
|---|---|---|
| gemicro-core | Traits (Agent, Tool, Interceptor), AgentContext, LlmClient, errors | Implementations |
| tools/* | One tool per crate | Other tools, agent logic |
| hooks/* | One hook per crate | Other hooks, agent logic |
| agents/* | One agent + its config/events | Other agents, core infra |
| gemicro-runner | AgentRunner, ExecutionState | Agent implementations |
| gemicro-eval | EvalHarness, Scorers | Agent implementations |
- New agent? →
agents/gemicro-{name}/ - New tool? →
tools/gemicro-{name}/ - New hook? →
hooks/gemicro-{name}/ - Cross-agent infrastructure? →
gemicro-core - NO CHANGES TO CORE TYPES for new agents/tools/hooks
// Use AgentUpdate::custom() for agent-specific events
yield Ok(AgentUpdate::custom("my_step", "Step complete", json!({})));
// AgentUpdate::final_result() is the ONLY required event (signals completion)
yield Ok(AgentUpdate::final_result(answer, metadata));Unknown event types must be logged and ignored, not treated as errors.
Config belongs in agent constructors, not shared context:
let agent = DeepResearchAgent::new(research_config); // Config here
let stream = agent.execute(query, context); // Context is minimalSee docs/AGENT_AUTHORING.md, docs/TOOL_AUTHORING.md, docs/INTERCEPTOR_AUTHORING.md.
Reference implementations:
- Agent:
agents/gemicro-prompt-agent/ - Tool:
tools/gemicro-file-read/ - Hook:
hooks/gemicro-audit-log/
- Streaming-first:
execute()returnsimpl Stream<Item = Result<AgentUpdate>>for real-time observability - Parallel sub-queries: Spawn via
tokio::spawn, results stream throughmpsc::channel - Timeout enforcement:
tokio::time::timeoutper phase with remaining time calculation - Partial failure:
continue_on_partial_failureconfig controls abort vs continue
- Unit tests: In-module
#[cfg(test)]blocks - Doc tests: Public API examples must compile
- Integration tests:
#[ignore], requireGEMINI_API_KEY, run with--include-ignored - Test helpers: Each crate has
tests/common/mod.rswithcreate_test_context()
| Fence | Behavior |
|---|---|
```rust |
Runs as test (default) |
```ignore |
Still compiles with --include-ignored, just doesn't run by default |
```text |
Pure documentation, no compilation |
Use ignore for examples that compile but require runtime dependencies (API keys, network). Use text for pseudo-code or conceptual examples that shouldn't compile.
Add to: Error enums, config structs, public data structs, serialized types
Skip for: Closed enums (ToolSet), unit structs, crate-internal types
- genai-rs: Published on crates.io
- tokio: Async runtime
- async-stream: Streaming agent implementations
Bump the version in Cargo.toml when new releases are published. Check the changelog for breaking changes before updating.
Always use gemini-3-flash-preview as the default model. Do not use older models like gemini-2.0-flash.
| Layer | Responsibility |
|---|---|
| genai-rs | Gemini API client, function calling, streaming |
| gemicro | Agent patterns, observability, tool orchestration |
Use genai-rs types directly when passing through. Wrap when adding functionality (recording, metadata).
Don't add to gemicro: Alternative LLM backends, Gemini API wrappers, complex workarounds (fix genai-rs instead).
Follow genai-rs patterns for consistency:
| Prefix | Meaning | Example |
|---|---|---|
with_* |
Configure/replace a setting | with_model(), with_text() |
add_* |
Accumulate to collection | add_function(), add_tools() |
as_* |
Accessor returning borrowed ref | as_text(), as_content() |
into_* |
Consuming conversion | into_string(), into_vec() |
Builder methods are chainable and return Self.
| Issue | Solution |
|---|---|
| "can't find crate" | Add to [workspace.members] in root Cargo.toml |
| Integration tests skipped | Set GEMINI_API_KEY; tests use #[ignore] |
make check fails but cargo test passes |
Run cargo fmt --all |
| "Unknown event type" warnings | Expected - consumers ignore unknowns |
| Tool confirmation hangs in tests | Use AutoApprove handler |
Keep docs updated when making user-facing changes:
| Change Type | Update |
|---|---|
| New/modified agent patterns | docs/AGENT_AUTHORING.md |
| New/modified markdown agent format | docs/MARKDOWN_AGENTS.md |
| New/modified tools | docs/TOOL_AUTHORING.md |
| New/modified hooks | docs/INTERCEPTOR_AUTHORING.md |
| Cross-cutting features | README.md "Cross-Cutting Concerns" table |
Rule: If you change how something works, update the doc that explains it.