This document provides a bird's-eye view of the soop please codebase. See also CLAUDE.md for development commands and conventions.
soop please is a TypeScript/Bun implementation of two research papers on repository-level code understanding and generation:
- RPG-Encoder (Code → Intent): Encodes a codebase into a Repository Planning Graph (RPG) — a hierarchical dual-view graph combining semantic features with structural metadata. The graph enables semantic search, dependency exploration, and agentic code navigation.
- RPG-ZeroRepo (Intent → Code): Generates repository code from high-level specifications using an RPG as the intermediate planning structure.
The core data structure is G = (V, E) where nodes carry { feature, metadata } pairs (semantic description + code entity info) and edges represent either feature hierarchy (functional) or code dependencies (imports, calls, data flow).
| Entry Point | File | Description |
|---|---|---|
| CLI | packages/cli/src/cli.ts |
soop command — encode, evolve, search, fetch, explore, init, sync |
| MCP Server | packages/mcp/src/server.ts |
JSON-RPC stdio server for Claude Code integration |
| Library API | packages/soop/src/index.ts |
Published npm package (@pleaseai/soop) — re-exports all public APIs |
| Build | tsdown.config.ts |
Produces library bundle + CLI binary into packages/soop/dist/ |
| Tests | vitest.config.ts |
Unit (*.test.ts) and integration (*.integration.test.ts) projects |
| Agent Evals | evaluation/ |
Agent evaluation framework using @vercel/agent-eval (soop vs baseline benchmarks) |
packages/
├── ast/ Layer 0 tree-sitter parser (multi-language AST extraction, native via namu)
├── utils/ Layer 0 Git helpers, LLM client, logger, memory utilities
├── store/ Layer 0 Storage interfaces & implementations
├── graph/ Layer 1 RPG data structures (Node, Edge, RPG class)
├── encoder/ Layer 2 Code → RPG extraction pipeline
├── tools/ Layer 2 Agentic graph navigation (SearchNode, FetchNode, ExploreRPG)
├── zerorepo/ Layer 2 Intent → Code generation pipeline
├── namu/ Layer 2 native tree-sitter backend (@kreuzberg/tree-sitter-language-pack) + NamuNode adapter
├── mcp/ Layer 3 MCP server exposing tools as JSON-RPC
├── cli/ Layer 4 Commander-based CLI entry point
├── soop/ Publish Umbrella package — bundles everything for npm
└── soop-native/ Publish Native binary distribution (bun compiled)
| Directory | Purpose |
|---|---|
evaluation/ |
Agent evaluation framework (@vercel/agent-eval) — benchmarks soop-assisted vs baseline coding agents |
agent-evals/ |
Evaluation experiment definitions and fixtures |
vendor/ |
Read-only git submodule with Python reference implementation (RPG-ZeroRepo) |
docs/ |
Research paper source files and implementation status |
tests/fixtures/ |
Shared test fixtures (e.g., superjson submodule for evolution tests) |
@pleaseai/soop-ast — WASM-based tree-sitter parser supporting TypeScript, JavaScript, Python, Rust, Go, Java, Kotlin, Ruby, C, C++, C#. Extracts CodeEntity objects (classes, functions, interfaces) from source files.
@pleaseai/soop-utils — Shared utilities with sub-path exports:
@pleaseai/soop-utils/llm— Multi-provider LLM client (Anthropic, OpenAI, Google via AI SDK; Claude Code, Codex CLI, and Gemini CLI as local providers)@pleaseai/soop-utils/git-helpers— Git operations (diff parsing, commit SHA, file listing)@pleaseai/soop-utils/logger—consola-based structured logging with tagged output@pleaseai/soop-utils/memory— Token-aware context management
@pleaseai/soop-store — Decomposed storage layer with three interface types:
| Interface | Implementations |
|---|---|
GraphStore |
SQLiteGraphStore (better-sqlite3, FTS5), SurrealGraphStore (embedded), LocalGraphStore (JSON) |
VectorStore |
LocalVectorStore (JSON, brute-force cosine), LanceDBVectorStore (optional) |
TextSearchStore |
LocalTextSearchStore (in-memory term-frequency), SQLite FTS5 |
Store implementations use sub-path exports (@pleaseai/soop-store/sqlite, @pleaseai/soop-store/local) to avoid transitive native module loading.
@pleaseai/soop-graph — Core RPG data structures:
RepositoryPlanningGraph— The central graph class managing nodes, edges, and backed by aContextStoreHighLevelNode/LowLevelNode— Architectural modules vs. atomic code entitiesFunctionalEdge/DependencyEdge/DataFlowEdge— Feature hierarchy, imports/calls, data flow- Schema validation via Zod for all graph data
@pleaseai/soop-encoder — The encoding pipeline:
- Semantic lifting (
semantic.ts) — LLM-based feature extraction from code entities - Structural reorganization (
reorganization/) — Domain discovery + hierarchy building - Artifact grounding (
grounding.ts) — Links nodes back to source locations - Data flow detection (
data-flow.ts) — Cross-file data flow analysis - Dependency injection (
dependency-injection.ts) — DI pattern detection - Evolution (
evolution/) — Commit-level incremental updates (add/modify/delete) - Semantic search (
semantic-search.ts) — Hybrid search (vector + FTS + string) - Embedding (
embedding.ts,embedding-manager.ts) — Multi-provider embedding (Voyage AI, HuggingFace local, OpenAI) - Caching (
cache.ts) — SQLite-based semantic response cache
@pleaseai/soop-tools — Agentic tools for graph navigation:
SearchNode— Semantic search by feature terms or file patternsFetchNode— Retrieve entity details and source codeExploreRPG— Traverse functional and dependency edges
@pleaseai/soop-zerorepo — Code generation from specifications (three phases: proposal-level feature tree, implementation-level file/function design, code generation with test-driven validation).
@pleaseai/soop-mcp — MCP server exposing six tools (soop_search, soop_fetch, soop_explore, soop_encode, soop_evolve, soop_stats) over JSON-RPC stdio transport.
@pleaseai/soop-cli — Commander-based CLI with commands: encode, evolve, search, fetch, explore, embed, init, sync, stamp, last-commit, mcp.
Source Code
│
▼
AST Parser ──────► CodeEntity[]
│
▼
Semantic Extractor ──► SemanticFeature[] (LLM or heuristic)
│
▼
Reorganization ──────► HighLevelNode[] (domain grouping + hierarchy)
│
▼
Grounding ───────────► LowLevelNode[] (file/class/function → node mapping)
│
▼
Dependency Analysis ──► DependencyEdge[] + DataFlowEdge[] (AST-based)
│
▼
RPG (graph.json) ────► Searchable graph with semantic + structural views
│
├──► MCP Server ──► Claude Code / AI agents
├──► CLI ──────────► Developer terminal
└──► Evolution ────► Incremental updates from new commits
.soop/
graph.json ← Tier 1: CI-managed canonical RPG (git committed)
config.json ← Encode/sync settings (git committed)
cache/ ← Semantic cache (gitignored)
local/ ← Tier 2: Local-only data (gitignored)
graph.json ← Local evolved copy
vectors/ ← Embedding indices
state.json ← Local state (base commit, branch)
Tier 1 (CI): GitHub Actions runs soop encode/soop evolve on main push, commits graph.json.
Tier 2 (Local): soop sync copies canonical graph, applies incremental evolve for branch changes, builds vector indices.
The project uses tsdown (Rolldown-based) for bundling:
- Library bundle →
packages/soop/dist/src/index.mjs— all@pleaseai/*workspace packages bundled inline; native deps (better-sqlite3,@kreuzberg/tree-sitter-language-pack,@lancedb/lancedb) remain external - CLI binary →
packages/soop/dist/packages/cli/src/cli.mjs— standalone CLI with all pure-JS deps bundled - Native binary →
packages/soop-native/— Bun-compiled native binary distribution
Workspace packages are all private: true and never published individually — only @pleaseai/soop is published to npm. Publishing uses bun pm pack (auto-resolves workspace:* to real versions) + npm publish <tarball>.
- Respect layer boundaries: Layer N packages may only import from Layer ≤ N. Never import
cliormcpfrom library packages. - Store isolation: Store implementations are NOT re-exported from the barrel index. Import via sub-paths (
@pleaseai/soop-store/sqlite) to avoid loading native modules unnecessarily. - Cross-package imports use workspace names: Always
@pleaseai/soop-graph, never../../graph/src. Within-package imports use relative paths. - Zero-dependency defaults:
LocalVectorStoreandLocalGraphStore(JSON-based) are the default storage. SQLite, SurrealDB, and LanceDB are opt-in backends. - RPG as concept name: Class names preserve "RPG" (
RepositoryPlanningGraph,RPGEncoder). Only brand/CLI/package names use "soop please". - No modifications to vendor/:
vendor/RPG-ZeroRepo/is a read-only git submodule containing the Python reference implementation. - English only: All code, comments, commits, issues, and PR descriptions are in English.
- Vitest with two workspace projects:
unit(fast,*.test.ts) andintegration(slow,*.integration.test.ts) - Test files live in
packages/*/tests/ - Integration tests use
tests/fixtures/superjsonsubmodule (real git history for evolution testing) - Git-history-dependent tests guarded with
it.skipIf(!hasGitAncestor(...)) - Run
bun run lint:fixafter editing test files (formatter/linter may disagree)
Logging: All packages use consola via @pleaseai/soop-utils/logger. Library packages call createLogger('Tag'), MCP server uses createStderrLogger('Tag') (stdout reserved for JSON-RPC). The --verbose CLI flag sets global log level to debug.
LLM Integration: Multi-provider support via AI SDK (@ai-sdk/anthropic, @ai-sdk/openai, @ai-sdk/google) plus local providers (claude-code, codex-cli, gemini-cli). Semantic cache (SQLite WAL) avoids redundant LLM calls.
Error Handling: MCP server uses typed RPGError classes. Encoder operations are designed to be resumable — semantic cache preserves progress across interrupted runs.
Configuration: Repository-level config in .soop/config.json. CLI reads .env.local / .env for API keys. Workspace settings in .please/config.yml.