Skip to main content

Deterministic code context from symbol graphs — not vector search

Project description

Stubborn

Deterministic code context from symbol graphs — for SCIP-indexed codebases.

Status: Beta (Java-first) — release 0.9.0b4 · BETA.md · POSITIONING.md · CHANGELOG

Stubborn compiles a SCIP symbol index into type-safe, privacy-preserving stub text for LLMs and agents. Same index + target + options → same context: reproducible, token-bounded, and stripped of method bodies.

Primary fit: Java / Spring repos (especially legacy modernization) where teams already run or can run scip-java. Also: Cursor/MCP users with a symbols.db who want deterministic context — not a zero-config repo map.

Independent project under stubborn-ai (program map). Full positioning: docs/POSITIONING.md.

This repo is a personal showcase of architecture-led, AI-assisted engineering: the developer defines system design, boundary protocols, and acceptance criteria; AI implements most of the code; the shipped artifact is deterministic Python — reproducible, test-gated, and verifiable (same SCIP → same context).

Development model → — human vs AI roles, deterministic core, boundary protocols.

Why Stubborn?

Real pain points: type hallucinations when LLMs lack declarations, token waste from whole files, privacy from leaking implementations, non-reproducible embedding chunks.

Stubborn addresses these when you already have (or can build) a SCIP index. Compare on three axes — not “us vs vector RAG” alone:

Stubborn Vector chunk RAG Low-friction symbol maps (e.g. Aider repo-map)
Determinism Same SCIP → same stub Chunk / embedding drift Varies
Type structure Symbol graph + signatures Arbitrary text spans Repo structure / tags
Setup friction SCIP index required Index / embed pipeline Open repo
Token KPI Built-in metrics, ~80–90% vs sources (Java E2E) Unpredictable Not a design goal
Privacy No method bodies by design May include full files Full files possible
CI reconcile diff, symbol guards Hard to baseline Uncommon

Stub = skeleton declarations (like header files).
Stubborn = compiles symbol graphs into bounded stub text; use --prune-mode strict when you want SCIP-proven neighbors only (ADR-003).

Use cases

Primary (Java / Spring + SCIP workflow):

  • Legacy / modernization — scoped context for large estates (examples/migration-bridge, dukesbank)
  • PR semantic auditdiff two SCIP indexes; CI symbol guards
  • Program runbooks — reproducible stub artifacts with compression KPIs

Secondary (agents / individuals):

  • Cursor / MCPget_context before codegen on a pre-built symbols.db
  • Large-repo onboarding — dependency skeleton for one target symbol

Start with 30-second fixture or Docker E2E; production Java path requires scip-java (see Requirements).

Requirements

  • Python 3.11+ (or use Docker)
  • A SCIP index for your project — Stubborn does not index source directly
Goal You need
Try Stubborn (no Java) Bundled fixture only — below
Real Java / Spring repo scip-java (or CI that produces index.scip) + stubborn index
Reproduce project E2E Docker Desktop — docker/README.md

Beta scope: weave quality and KPIs are Java-validated. Other SCIP languages may ingest; output quality is not guaranteed until language-specific E2E ships (BETA.md).

Docker quick start

docker compose build
docker compose run --rm e2e    # demo-spring E2E
docker compose run --rm petclinic-e2e  # spring-petclinic scale-up
docker compose run --rm cli --help

See docker/README.md.

Installation

PyPI: stubborn-stub · CLI: stubborn (alias: stub)

pip install stubborn-stub

From source (development):

git clone https://github.com/stubborn-ai/stubborn.git
cd stubborn
pip install -e ".[dev]"

Try in 30 seconds (no Java required)

Uses the bundled minimal SCIP fixture — no JDK, Maven, or scip-java needed:

pip install stubborn-stub
stubborn index --scip examples/fixtures/minimal.scip --out /tmp/symbols.db
stubborn info /tmp/symbols.db
stubborn context /tmp/symbols.db \
  --target "semanticdb maven com/example/OrderService#" \
  --out /tmp/order-service.stub.java

Quick start

Full E2E with a modern Spring Boot demo: see examples/demo-spring.

1. Index symbols

# Binary SCIP from scip-java (recommended)
stubborn index --scip index.scip --out ./metadata/symbols.db

# Or use the bundled fixture while bootstrapping
stubborn index \
  --scip examples/fixtures/minimal.scip \
  --out ./metadata/symbols.db

2. Inspect

stubborn info ./metadata/symbols.db

3. Get LLM context for a target symbol

stubborn context ./metadata/symbols.db \
  --target "semanticdb maven com/example/OrderService#process()." \
  --out ./context/order-service.stub.java

# Compact cross-language format (~fewer tokens):
stubborn context ./metadata/symbols.db \
  --target "semanticdb maven com/example/OrderService#process()." \
  --format stubborn-dsl \
  --out ./context/order-service.stubborn-dsl

See docs/STUBBORN-DSL.md for the compact cross-language format.

Choose output format:

Project Suggested --format
Pure Java / Spring codegen java-stub (default)
Mixed-language or token-sensitive / graph-first stubborn-dsl

Tune output granularity: --member-signatures off|target|neighbors|all, --javadoc off|summary|full (guide).

Choose neighbor expansion (--prune-mode):

Mode When
smart (default) Richest type neighbors; CI guards assume this
strict SCIP-proven edges only — no signature heuristics
fast Smaller neighborhood + no heuristics — tight token budget

Or use the short CLI alias: stub.

4. Reconcile before/after (CI-friendly)

stubborn diff ./metadata/before.db ./metadata/after.db
# exit 1 if symbols are missing

5. MCP server (Cursor / agents)

Use the separate stubborn-mcp package:

pip install stubborn-mcp
export STUBBORN_DB=./metadata/symbols.db
stubborn-mcp

Tools: get_context, list_symbols, metrics. See stubborn-mcp docs.

CLI

Command Description
init-db Create empty SQLite symbol graph
index Ingest SCIP (.scip, .scip.ndjson, or .json fixture)
info Index run summary
context Prune graph → emit LLM context (--format java-stub | stubborn-dsl; --prune-mode smart | strict | fast)
metrics Compression KPI: stub vs full Java sources
diff Symbol set reconcile (missing/extra)

Architecture

Design rationale is recorded as Architecture Decision Records (docs/adr/). Pipeline overview:

[Source code] → scip-java / scip-clang / … → index.scip
       ↓
  stubborn index → SQLite symbol graph
       ↓
  stubborn context → stub text (java-stub or stubborn-dsl)
       ↓
  LLM / Agent / CI

SQLite schema: src/stubborn/store/schema/v1.sql

Roadmap

Version Focus
0.1 SQLite schema, JSON fixture ingest, Java stub weaver, CLI shell
0.2 Binary .scip protobuf ingest, .scip.ndjson, scip-java compatible
0.3 Token budget enforcement, metrics KPI, weaver quality, Docker CI
0.4 MCP server (get_context, list_symbols, metrics)
0.5 Type-neighbor pruning, PR symbol-diff Action, context guard
0.6 spring-petclinic scale-up E2E (~90% savings)
0.7 Stubborn-DSL weaver (--format stubborn-dsl)
0.8 Java-first beta track — BETA.md, demo-spring cases
0.9 Method signatures, STUBBORN-DSL-GUIDE
0.9.0b3 (now) Standalone cleanup — rename debt removed, ruff CI, CLI smoke tests
0.9.0b2 Java-first Beta — classifier + weave granularity switches
1.0 Multi-language E2E, stable API

Documentation

Doc Description
docs/DEVELOPMENT-MODEL.md Architecture-led, AI-assisted development model
docs/adr/README.md Architecture Decision Records (design rationale)
docs/POSITIONING.md Product positioning — audience, competitors, honest scope
docs/BETA.md Beta checklist, limitations, KPI baselines
docs/STUBBORN-DSL.md Stubborn-DSL grammar
docs/STUBBORN-DSL-GUIDE.md java-stub vs stubborn-dsl decision guide
docs/STUBBORN-DSL-LLM.txt LLM system-prompt snippet
docs/MCP.md Cursor / agent integration
docs/SCIP-INGEST.md SCIP ingest
examples/README.md E2E examples

Optional ecosystem integrations

Stubborn is standalone. Some teams also use it alongside the anchor-migration program:

Repo Role
stubborn (this repo) LLM context compiler
migration-hub Optional program docs — integration guide
java-ast-ssot Full Java AST SSOT (complementary)
db-metadata Database schema SSOT (complementary)

See docs/POSITIONING.md.

Development

pip install -e ".[dev]"
pytest -v
ruff check src tests
ruff format --check src tests

MCP server (stubborn-mcp):

pip install -e "../stubborn-mcp"
stubborn-mcp

License

MIT — see LICENSE.

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

stubborn_stub-0.9.0b4.tar.gz (37.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

stubborn_stub-0.9.0b4-py3-none-any.whl (42.6 kB view details)

Uploaded Python 3

File details

Details for the file stubborn_stub-0.9.0b4.tar.gz.

File metadata

  • Download URL: stubborn_stub-0.9.0b4.tar.gz
  • Upload date:
  • Size: 37.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for stubborn_stub-0.9.0b4.tar.gz
Algorithm Hash digest
SHA256 98e9c1f8fcb9ab20ec2e0eb1c8cb9aa2194b95e99297dafc653e8067069d5f95
MD5 2bbbf92caaed39254f955a23ab9766f5
BLAKE2b-256 fafab6d30755cee0ace25d55037b8f22921340ddea002eb4a1a520083e953c5a

See more details on using hashes here.

File details

Details for the file stubborn_stub-0.9.0b4-py3-none-any.whl.

File metadata

File hashes

Hashes for stubborn_stub-0.9.0b4-py3-none-any.whl
Algorithm Hash digest
SHA256 7faa322a6900e0c5b052798124e2bd644951965b026eb595d8a524372646e66b
MD5 142fac7cb3fdb3dc13eb7955a7fd44cc
BLAKE2b-256 234dc49f2f2c6d022beccc4dd83a30649dee317e4ae6d59dde938b576961abe9

See more details on using hashes here.

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