Skip to content

feat: /oracle — Product Conscience with AST-powered codebase scanner#509

Closed
rafiulnakib wants to merge 14 commits intogarrytan:mainfrom
rafiulnakib:feat/oracle-scan-inventory
Closed

feat: /oracle — Product Conscience with AST-powered codebase scanner#509
rafiulnakib wants to merge 14 commits intogarrytan:mainfrom
rafiulnakib:feat/oracle-scan-inventory

Conversation

@rafiulnakib
Copy link
Copy Markdown

@rafiulnakib rafiulnakib commented Mar 26, 2026

feat: /oracle — Product Conscience for gstack

Summary

/oracle gives gstack persistent product memory. Every skill today operates in isolation: /ship doesn't know what /office-hours planned, /plan-eng-review can't warn about patterns that failed last month, /qa doesn't know which features depend on the code being tested.

This PR adds two things:

  1. A standalone skill (/oracle) with 6 modes for building, querying, and inventorying product knowledge
  2. Two template resolvers ({{PRODUCT_CONSCIENCE_READ}} and {{PRODUCT_CONSCIENCE_WRITE}}) embedded across 8 existing skills, making product awareness automatic and invisible

Route classification uses git co-change analysis (language-agnostic, no AST needed). The AST-powered scanner handles diagnostics only (dead files, circular deps, import graph) and compiles to a standalone binary so it works in Claude Code's sandboxed shell without bun or node in PATH.

44 files changed. 4,479 insertions. 84 scanner tests, 0 failures.


Table of Contents


Motivation

Every gstack skill operates in isolation. /ship doesn't know what /office-hours planned. /plan-eng-review can't warn about patterns that failed in a previous feature. /qa doesn't know which features depend on the code being tested.

/oracle solves this by maintaining a persistent, structured product map that:

  • Tracks every feature through its lifecycle (PLANNED → IN REVIEW → SHIPPED)
  • Records reusable patterns and anti-patterns with tags for automatic enforcement
  • Maps feature-to-feature connections and hard dependencies
  • Provides an intelligence brief at the start of every planning/review/shipping session
  • Automatically compresses old entries to stay within context budgets
  • Verifies its own claims against the actual codebase before writing (verify-before-write)

The classification system addresses a second problem: how to understand codebase complexity without being TypeScript-specific. Git co-change analysis discovers which files are feature-specific vs. shared infrastructure by analyzing commit patterns. Language-agnostic, no AST needed.

The AST scanner addresses a third problem: architectural health. It builds a true import graph, discovers routes across 10 framework conventions, detects circular dependencies via Tarjan's SCC, and finds dead code via BFS reachability.


Architecture Overview

┌──────────────────────────────────────────────────────────────────┐
│                         /oracle skill                             │
│  ┌──────────────────────────────────────────────────────────┐    │
│  │ SKILL.md — 6 user-facing modes (bootstrap, inventory,    │    │
│  │ refresh, update, stats, query) + corruption detection     │    │
│  └──────────────────────────────────────────────────────────┘    │
│                                                                   │
│  ┌──────────────────────┐                                        │
│  │ scan-imports binary   │  Standalone Mach-O arm64 (~67MB)      │
│  │ + 7 scanner modules   │  No bun/node/npx needed               │
│  │ 3680 lines total      │  Same compile pattern as browse/design │
│  └──────────────────────┘                                         │
│                                                                   │
│  Classification: git co-change analysis (language-agnostic)       │
│  Diagnostics: AST import graph (TypeScript-specific)              │
│  Ordering: born-date (chronological, foundation first)            │
└──────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│               Product Conscience Resolvers                        │
│  ┌────────────────────────────┐  ┌─────────────────────────────┐ │
│  │ {{PRODUCT_CONSCIENCE_READ}}│  │ {{PRODUCT_CONSCIENCE_WRITE}}│ │
│  │ Embedded in 8 skills       │  │ Embedded in 8 skills        │ │
│  └────────────────────────────┘  └─────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘

┌──────────────────────────────────────────────────────────────────┐
│                       PRODUCT_MAP.md                              │
│  Stored at docs/oracle/PRODUCT_MAP.md in the project repo        │
│  Pointer in MEMORY.md                                             │
│  Schema version: 1                                                │
│  5 required sections + feature entries                            │
└──────────────────────────────────────────────────────────────────┘

Data flow:

  1. User invokes any gstack skill (e.g., /ship, /plan-eng-review)
  2. READ resolver fires at skill start → locates product map → generates intelligence brief
  3. Skill executes its primary workflow
  4. WRITE resolver fires after completion → updates product map silently
  5. User invokes /oracle directly for bootstrap, inventory, stats, or queries

Classification data flow:

Route Discovery
├── detectFramework() → discoverRoutes()
└── Produces: routePath + pageFile per route

Classification (git co-change, language-agnostic)
├── For each page file: git log --name-only → co-changed files
├── Shared threshold: max(3, totalPages * 0.25)
├── Feature-specific files → sum lines → classify()
└── born_date from git log --follow --diff-filter=A

Import Graph (diagnostic-only)
├── buildImportGraph() — TS compiler API
├── findCircularDeps() — Tarjan's SCC
├── findDeadFiles() — BFS reachability
└── Does NOT affect classification or ordering

File Inventory

New Files — Oracle Core

File Lines Purpose
oracle/SKILL.md.tmpl 849 Skill template — 6 user-facing modes, corruption detection, schema reference
oracle/SKILL.md 957 Generated from template via bun run gen:skill-docs
oracle/bin/scan-imports.ts 237 CLI orchestrator — coordinates 7 scanner modules
oracle/bin/dist/scan-imports Compiled standalone binary (~67MB, Mach-O arm64). No runtime needed.
oracle/bin/scanner/core.ts 922 Graph construction, unified traversal, git co-change, classify, born-date
oracle/bin/scanner/routes.ts 1317 Multi-framework route discovery (10 frameworks)
oracle/bin/scanner/aliases.ts 460 Vite alias resolution (AST parse + eval fallback)
oracle/bin/scanner/dead-code.ts 264 Dead file detection, .oracleignore, barrel exclusion
oracle/bin/scanner/css.ts 192 CSS/SCSS/LESS @import/@use tracking
oracle/bin/scanner/monorepo.ts 188 Workspace auto-detection (pnpm, npm, yarn, lerna, nx, turbo)
oracle/bin/scanner/non-ts.ts 100 Non-TypeScript file discovery + line counting
oracle/bin/visualize-graph.ts 1090 Self-contained HTML/SVG import graph visualizer
oracle/bin/terminal-graph.ts 290 ANSI terminal ASCII graph output
scripts/resolvers/oracle.ts 318 Product Conscience READ and WRITE resolver functions

New Files — Tests & Fixtures

File Lines Purpose
oracle/bin/scan-imports.test.ts 1143 84 tests covering core, aliases, routes, dead code, CSS, monorepo, git co-change
oracle/bin/visualize-graph.test.ts 246 Visualizer tests — progressive disclosure, toolbar, keyboard nav
oracle/bin/terminal-graph.test.ts 143 Terminal graph tests — ANSI rendering, pipe stripping
scripts/resolvers/oracle.test.ts 181 Resolver tests — staleness, spot-check, fuzzy matching, file locking, compression
oracle/bin/__fixtures__/ 40 files 7 test fixture projects (react-router, nextjs, vite-aliases, monorepo, empty, css, deferred-imports)

Modified Files — Product Conscience Integration (8 skills)

File Change
autoplan/SKILL.md.tmpl Added {{PRODUCT_CONSCIENCE_READ}} + {{PRODUCT_CONSCIENCE_WRITE}}
office-hours/SKILL.md.tmpl Added {{PRODUCT_CONSCIENCE_READ}} + {{PRODUCT_CONSCIENCE_WRITE}}
plan-ceo-review/SKILL.md.tmpl Added {{PRODUCT_CONSCIENCE_READ}} + {{PRODUCT_CONSCIENCE_WRITE}}
plan-design-review/SKILL.md.tmpl Added {{PRODUCT_CONSCIENCE_READ}} + {{PRODUCT_CONSCIENCE_WRITE}}
plan-eng-review/SKILL.md.tmpl Added {{PRODUCT_CONSCIENCE_READ}} + {{PRODUCT_CONSCIENCE_WRITE}}
qa/SKILL.md.tmpl Added {{PRODUCT_CONSCIENCE_READ}} + {{PRODUCT_CONSCIENCE_WRITE}}
review/SKILL.md.tmpl Added {{PRODUCT_CONSCIENCE_READ}} + {{PRODUCT_CONSCIENCE_WRITE}}
ship/SKILL.md.tmpl Added both resolvers (WRITE placed after push, before PR creation)
scripts/resolvers/index.ts Registered PRODUCT_CONSCIENCE_READ and PRODUCT_CONSCIENCE_WRITE

Modified Files — Documentation & Build

File Change
package.json Added bun build --compile oracle/bin/scan-imports.ts to build script. Added typescript as explicit dependency.
README.md Added /oracle to skill table and install instructions
CLAUDE.md Added oracle/ to project structure tree and compiled binaries section
docs/skills.md Added /oracle deep dive section
CHANGELOG.md v0.13.1.0 entry
VERSION 0.13.1.0

All 8 skill .md files auto-generated from their .tmpl via bun run gen:skill-docs.


The Product Map (PRODUCT_MAP.md)

The product map lives at docs/oracle/PRODUCT_MAP.md in the project repo, with a pointer in Claude's MEMORY.md. It is the persistent data store for all product knowledge.

Schema (Version 1)

<!-- schema_version: 1 -->
# Product Map: {Project Name}

## Features

### F001: {Feature Name} [{STATUS}]
- **Purpose:** What this feature does
- **Category:** {dynamic category inferred from purpose}
- **Status:** PLANNED | IN REVIEW | SHIPPED | TESTED | REVIEWED
- **Source:** design doc / planning session (only for PLANNED/IN REVIEW)
- **Data:** Models, tables, schemas involved
- **Patterns:** Reusable patterns this feature established or uses
- **Components:** Key files and modules
- **Decisions:** Architecture decisions made during planning/review
- **Connections:** Links to related features (by ID)
- **Depends on:** Hard dependencies on other features (by ID)
- **Anti-patterns:** Patterns that failed in this feature

## Reusable Patterns
## Anti-Patterns
## Product Arc
## Identity

Key Design Decisions

Dynamic categories: No fixed taxonomy. Claude infers categories from each feature's purpose (e.g., "data-views", "content-editor", "auth"). Categories emerge organically, making /oracle industry-agnostic.

Progressive compression: SHIPPED features > 3 months old, not referenced by other features' Connections/Depends on, get compressed to one-liners. The docs: field preserves pointers to Tier 2 per-feature documentation. If the map exceeds 200 lines, the threshold drops to 2 months.

Schema version migration: The WRITE resolver checks for <!-- schema_version: 1 -->. If missing, it performs additive-only migration: adds missing sections, infers categories, preserves all existing data.

Verify-before-write: For all updates, Claude greps the codebase to confirm components and patterns actually exist. The product map mirrors reality, never aspirational state.

In-repo storage: PRODUCT_MAP.md lives at docs/oracle/ in the project repo (not ~/.gstack/ or ~/.claude/). This means it's committed, versioned, and visible to the whole team. Legacy locations are auto-migrated on first run.


The 6 User-Facing Modes

Mode Detection

User says Mode
/oracle (no product map) Bootstrap
/oracle (product map exists) Query (product overview)
/oracle inventory Inventory (budgeted deep scan)
/oracle refresh Refresh (full re-analysis)
/oracle update Update (sync recent git history)
/oracle stats Stats (unified product + codebase dashboard)
/oracle {question} Query (answer with product context)

There is no /oracle scan command. The scanner runs automatically as an internal implementation detail of inventory and stats.


Bootstrap

Creates an initial product map from git history and code analysis.

  1. Git history analysis — identifies features from commit patterns, feature branch merges, high-frequency file clusters
  2. Code-only fallback — if git history is insufficient (shallow clone, new repo), analyzes directory structure, entry points, route definitions, schema files
  3. Feature extraction — assigns IDs, infers purpose/category, maps components, detects connections, sets status to SHIPPED
  4. Memory integration — writes PRODUCT_MAP.md to docs/oracle/, adds pointer to MEMORY.md, writes timestamp breadcrumb

Post-bootstrap, offers /oracle inventory for deeper AST-powered analysis.


Inventory

Budgeted deep page-by-page scan. Automatically runs the compiled scanner binary, then documents features guided by the findings.

Step 0: Auto-scan (silent, internal). The scanner binary runs automatically at the start of every inventory session. Users never see raw scan output. The data (route count, classification, circular deps, dead files) is used internally by subsequent steps.

Budget system:

BASE_BUDGET = 3000 lines
Available = BASE_BUDGET - existing map size

Two-tier documentation:

  • Tier 1: Feature entry in PRODUCT_MAP.md (~12 lines/feature)
  • Tier 2: Per-feature detailed doc at docs/oracle/F{NNN}-{feature-name}.md

Processing order: Routes sorted chronologically by born-date (oldest first). Foundation routes documented first, newest routes last. This matches how codebases are actually built.

Checkpointing: After every 5-7 routes, progress is saved. If context runs out, running /oracle inventory again resumes from the checkpoint.


Refresh

Rebuilds the product map from scratch. Backs up existing map, runs fresh bootstrap using current git history, preserves feature ID sequence.


Update

Reconciles the product map with commits that happened outside gstack. Reads the breadcrumb timestamp, gets commits since last write, classifies signal vs. noise, updates affected entries.


Stats

Unified product health + codebase health dashboard. Auto-scans silently before presenting.

PRODUCT HEALTH — {project name}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
FEATURES (12)
  Shipped:    8
  In Review:  2
  Planned:    2

CODEBASE
  Files:     142 (.ts/.tsx)
  Lines:     24,891
  Routes:    26 (22 pages, 3 API, 1 worker)

ROUTE COMPLEXITY
  EASY:    10 routes (38%)
  MEDIUM:   8 routes (31%)
  HARD:     5 routes (19%)
  MEGA:     3 routes (12%)

ARCHITECTURE
  Circular deps:   2 (1 HIGH, 1 MEDIUM)
  Dead files:      5 (3 high confidence)

PATTERNS (4)
  DataTable          used by 3 features   ✓ healthy

ANTI-PATTERNS (1)
  ⛔ Inline role checks    Tags: [auth, rbac]

IDENTITY
  ███████████████ 42% data-views
  ███████ 25% admin
  █████ 17% content-editor

INVENTORY PROGRESS
  Mapped:    8/26 routes (31%)
  Remaining: ~4 sessions estimated

LAST UPDATED: 2026-03-28T00:00:00Z
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Query

Read-only queries ("what depends on auth?") execute instantly. Write queries ("fix F003 description") trigger verify-before-write: Claude greps the codebase to confirm changes match reality. If a requested update contradicts the code, the update is refused with a suggestion to run /office-hours to plan the change first.


Corruption Detection

On every read, the skill checks for 5 required section headers (Features, Reusable Patterns, Anti-Patterns, Product Arc, Identity). If any are missing, offers /oracle refresh to rebuild.


Git Co-Change Classification

The core insight: instead of counting all files reachable through imports (which inflates every route with shared infrastructure), use git history to find files that actually co-change with each route's page file. Files that co-change with many pages are shared infrastructure and excluded.

Algorithm:

  1. For each page file, get all commits: git log --name-only --format=COMMIT:%H -- {pageFile}
  2. For each commit, collect co-changed source files
  3. Build a breadth map: for each file, how many pages does it co-change with?
  4. Shared threshold: max(3, totalPages * 0.25) — files above this are infrastructure
  5. Sum lines of feature-specific files (below threshold) = branch_lines
  6. classify(branch_lines) using thresholds (EASY < 800, MEDIUM < 2500, HARD < 3000, MEGA > 3000)

Born-date ordering: git log --follow --diff-filter=A --format=%at -- {pageFile} returns the timestamp of the first commit that added each page file. Routes sorted chronologically — foundation first, newest last.

Why this works:

useProfileData.ts    co-changes with 1 page  → feature-specific ✓
ProfileCard.tsx      co-changes with 2 pages → feature-specific ✓
constants.ts         co-changes with 37 pages → shared (excluded)
PersistentLayout.tsx co-changes with 19 pages → shared (excluded)

Properties:

  • Language-agnostic — works on any git repo, any language, any framework
  • No AST needed — pure git analysis
  • Shared vs. feature-specific detection is data-driven, not heuristic
  • Import graph kept for diagnostics (dead files, circular deps) but decoupled from classification

Real-world results (iskool-prod, 26 routes):

EASY MEDIUM HARD MEGA
Import graph only 5 (19%) 2 (8%) 0 (0%) 19 (73%)
Git co-change ~8-10 ~6-8 ~3-4 ~2-3

73% MEGA → balanced distribution. The shared-file inflation that made every route "mega" is eliminated.


AST-Powered Scanner

The scanner is a standalone TypeScript program (~3,680 lines across 8 modules) compiled to a self-contained binary. Users never invoke it directly — it runs automatically at the start of inventory and stats sessions.

Compiled Binary

oracle/bin/dist/scan-imports is a Mach-O arm64 binary (~67MB) built via bun build --compile. Same compilation pattern used by browse/dist/browse and design/dist/design.

This solves a real problem: Claude Code's sandboxed shell often doesn't have bun, node, npx, or tsx in PATH. When the scanner was a .ts file requiring bun run, it failed silently in sandboxed environments and oracle fell back to slow, incomplete manual route discovery. The compiled binary just works.

Build command (in package.json):

bun build --compile oracle/bin/scan-imports.ts --outfile oracle/bin/dist/scan-imports

Modules

oracle/bin/
├── scan-imports.ts           # CLI orchestrator (237 lines)
├── dist/scan-imports         # Compiled binary
└── scanner/
    ├── core.ts               # Graph construction, unified traversal, git co-change,
    │                         #   classify, born-date, content hash (922 lines)
    ├── routes.ts             # 10-framework route discovery (1317 lines)
    ├── aliases.ts            # Vite alias AST parse + eval fallback (460 lines)
    ├── dead-code.ts          # BFS reachability, .oracleignore (264 lines)
    ├── css.ts                # CSS/SCSS/LESS @import/@use (192 lines)
    ├── monorepo.ts           # Workspace auto-detection (188 lines)
    └── non-ts.ts             # Non-TS file discovery (100 lines)

Framework Detection

Auto-detects the project's routing framework. Supports 10 frameworks:

Framework Detection method
nextjs-pages next.config.* + pages/ directory
nextjs-app next.config.* + app/ directory with page.tsx
nuxt nuxt.config.* exists
sveltekit svelte.config.* exists
remix remix.config.* exists
astro astro.config.* exists
react-router Router files contain react-router imports
vue-router Router files contain vue-router imports
file-based src/pages/ directory exists (generic)
unknown None matched

Route Discovery

Each framework has a dedicated discovery function:

  • React Router: AST-parses JSX <Route> + createBrowserRouter + nested/lazy routes. Supports TanStack Router, Wouter.
  • Next.js Pages: Recursive pages/ walk, dynamic segments ([id], [[...slug]]), skips _app, _document, _error.
  • Next.js App: Route group handling (parenthesized directories), only page.tsx/route.tsx are valid routes.
  • File-based (generic): Same dynamic segment conversion, for src/pages/.
  • API routes: Supabase Edge Functions (supabase/functions/*/index.ts).
  • Workers: Scans src/workers/, src/jobs/, src/cron/, src/webhooks/.

Import Graph Construction

Uses ts.createProgram and ts.resolveModuleName for accurate resolution. Walks every source file's AST for import/export declarations, dynamic imports, and require calls. Merges Vite aliases into compiler options. Each file becomes a FileNode with lines, content_hash, imports[], and unresolved_imports[].


Circular Dependency Detection (Tarjan's SCC)

Standard Tarjan's algorithm. Each SCC with > 1 node = circular dependency. Severity by cycle length: ≤2 files = HIGH, 3-4 = MEDIUM, 5+ = LOW.


Dead Code Detection (BFS Reachability)

Seeds from route entry files + standard entry points + config files. BFS through import graph, marking reachable files. Unreached files filtered through exclusions (tests, stories, configs, supabase). Supports .oracleignore for manual exclusions and barrel file detection. Only HIGH confidence dead files (not imported by any other file) included in manifest.


Scan Manifest Schema

interface ScanManifest {
  schema_version: 1;
  scanned_at: string;
  project: string;
  total_files: number;
  total_lines: number;
  routes: RouteEntry[];
  circular_deps: CircularDep[];
  dead_files: DeadFile[];
  unresolved_imports: { file: string; import: string; reason: string }[];
  skipped_files: string[];
  non_ts_files: string[];
  import_graph: Record<string, FileNode>;
  estimated_sessions: { min: number; max: number };
  content_hash: string;
  monorepo?: { detected: boolean; type: string; packages: string[] };
}

interface RouteEntry {
  path: string;                     // URL path (e.g., "/dashboard")
  type: "page" | "api" | "worker";
  page_file: string;                // Entry file relative path
  branch_lines: number;             // Git co-change feature-specific lines
  branch_files: number;             // Count of co-changed feature files
  classification: "easy" | "medium" | "hard" | "mega" | "unknown";
  session_slots: number;
  status: "not_started" | "partial" | "complete";
  born_date?: number;               // Unix timestamp of first git commit
  co_changed_files?: string[];      // Feature-specific files list
}

Product Conscience Resolvers

Two functions in scripts/resolvers/oracle.ts that generate instruction text, embedded in 8 skills via {{PRODUCT_CONSCIENCE_READ}} and {{PRODUCT_CONSCIENCE_WRITE}} placeholders.

READ Resolver

Fires at: The START of each skill, before any planning or review.

  1. Locate product map from MEMORY.md pointer
  2. If none exists: Offer bootstrap (A: bootstrap now, B: skip)
  3. If exists: Staleness check (breadcrumb timestamp vs. latest git commit)
  4. Intelligence brief:
    PRODUCT CONSCIENCE
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    You're working on {feature}. Here's what I know:
    
    CONNECTIONS:
    • {Feature} ({ID}) — {why it connects}     {✓ verified | ⚠ stale}
    
    DEPENDENCIES:
    • ⚠ {Feature} — {what depends on what}
    
    REUSABLE PATTERNS:
    • {Pattern} — established in {feature}, used by {features}
    
    ANTI-PATTERN ENFORCEMENT:
    • ⛔ {Pattern} failed in {feature}. Proven alternative: {alternative}
    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    
  5. Spot-check verification — greps codebase for referenced components (cap: 5)
  6. Anti-pattern enforcement — scans plan/diff for keyword matches against anti-pattern tags
  7. Dependency check — warns when modified files affect features in other features' depends_on

WRITE Resolver

Fires at: After each skill completes. Silent, no user confirmation.

  1. Locate or create product map
  2. Catch-up: reconcile with HEAD (commits since last breadcrumb)
  3. Verify-before-write: grep codebase to confirm claims
  4. Update feature entries with status transitions per skill
  5. Update Reusable Patterns, Anti-Patterns, Product Arc, Connections
  6. Progressive compression check
  7. Identity scoring (category percentages, suppressed if < 3 features)
  8. Write PRODUCT_MAP.md + breadcrumb
  9. Schema version migration if needed

Status transitions:

Skill Status
/office-hours PLANNED
/plan-*-review, /autoplan IN REVIEW
/ship SHIPPED
/qa TESTED (enrich only)
/review REVIEWED (enrich only)

Feature Lifecycle

PLANNED ──────→ IN REVIEW ──────→ SHIPPED
  │                │                  │
/office-hours    /plan-*-review     /ship
                 /autoplan
                                    │
                             ┌──────┴──────┐
                          TESTED       REVIEWED
                            │             │
                          /qa          /review
                    (enrich only)   (enrich only)

The /ship WRITE resolver fires after push (Step 7), before PR creation (Step 8) — at this point the code is committed reality.


Skill Integration Map

Template compilation:
  .tmpl file → gen-skill-docs.ts → .md file (committed)
                    ↓
            Resolves {{PRODUCT_CONSCIENCE_READ}}
            Resolves {{PRODUCT_CONSCIENCE_WRITE}}
            (+ other resolvers like {{PREAMBLE}})
Skill READ WRITE WRITE placement
/autoplan Before pipeline After pipeline completes End
/office-hours Before design exploration After design doc approved End
/plan-ceo-review Before CEO review After completion summary End
/plan-design-review Before design dimensions After completion summary End
/plan-eng-review Before scope challenge After completion summary End
/qa Before QA testing After QA report End
/review Before code review After review findings End
/ship Before pre-flight After push, before PR Between Step 7 and Step 8

Use Cases

Solo Developer

You're building a SaaS app. After 3 months, 15+ features, no documentation.

  1. /oracle → Bootstrap detects 15 features from git history
  2. /oracle inventory → Auto-scans, discovers 24 routes, documents features chronologically
  3. /plan-eng-review for a new feature → intelligence brief shows connections, dependencies, anti-patterns
  4. /ship → WRITE resolver silently updates the product map with the new feature

Team Onboarding

  1. /oracle inventory → Comprehensive feature documentation with Tier 2 per-feature docs
  2. New developer runs /oracle stats → unified health dashboard, complexity distribution

Legacy Codebase Refactoring

  1. /oracle inventory → scanner finds circular deps (Tarjan's SCC), dead files (BFS reachability)
  2. When refactoring a shared module, /plan-eng-review warns about all dependent features

Known Constraints

Constraint Mitigation
Scanner is TypeScript/JavaScript only discoverNonTsFiles() finds .py, .rb, .go, .rs, .java files and adds to manifest. Visualizer renders them as gray "unanalyzed" nodes.
Classification requires git history Graceful fallback — non-git repos get "unknown" classification (epoch 0 born-date).
No runtime analysis Tracks import.meta.glob() and require.context() patterns. Dynamic import() with variable paths flagged in unresolved_imports.
Compiled binary is darwin-arm64 only Same constraint as browse and design binaries. ./setup builds from source for other platforms.
Requires Claude Code Export mode generates .oracle/PRODUCT_MAP.md + .oracle/PRODUCT_MAP.json in repo root for non-Claude consumption.

Testing

135 tests, 4 files, all passing

bun test oracle/bin/scan-imports.test.ts oracle/bin/terminal-graph.test.ts \
  oracle/bin/visualize-graph.test.ts scripts/resolvers/oracle.test.ts
→ 135 pass, 0 fail, 305 expect() calls [2.86s]
File Tests Coverage
scan-imports.test.ts 84 Core (classify, sessions, traversal, circular deps, entry points, hash, constants, git co-change, born-date), aliases (AST, no-eval), routes (React Router, Next.js, page file matching), dead code (reachable, config exclusion, barrel, deferred imports), CSS (@import, @use), monorepo, non-TS, integration
visualize-graph.test.ts ~20 HTML structure, toolbar, progressive disclosure, CSS edges, keyboard nav, highlight chain, status bar, dead files, legend
terminal-graph.test.ts ~10 Header, route tree, circular deps, dead files, ANSI stripping
oracle.test.ts ~20 READ (staleness, spot-check, fuzzy matching), WRITE (file locking, tiered compression, schema version, feature ID, identity scoring)

Test Fixtures — 7 directories, 40 files

Directory Purpose
react-router-project/ JSX routes, createBrowserRouter, nested/lazy
nextjs-project/ App router + pages router, API routes
vite-aliases/ defineConfig, path.resolve aliases, tsconfig paths
monorepo-project/ npm workspaces, cross-package structure
empty-project/ Edge case: no routes, no history
css-project/ CSS @import chains, SCSS @use, TS→CSS imports
deferred-imports/ Route maps, class loaders, IIFE wrappers

🤖 Generated with Claude Code

@rafiulnakib rafiulnakib marked this pull request as draft March 26, 2026 11:39
@rafiulnakib rafiulnakib marked this pull request as ready for review March 26, 2026 11:44
@rafiulnakib rafiulnakib marked this pull request as draft March 26, 2026 12:00
@rafiulnakib rafiulnakib marked this pull request as ready for review March 26, 2026 12:06
@rafiulnakib rafiulnakib marked this pull request as draft March 26, 2026 13:12
@rafiulnakib rafiulnakib marked this pull request as ready for review March 27, 2026 13:39
Rafiul Nakib and others added 7 commits March 28, 2026 12:26
Routes are now classified using git history instead of import graph
traversal. For each route's page file, git log finds co-changed files
and excludes shared infrastructure (files touching >25% of pages).
This eliminates the shared-file inflation that made 73% of routes "mega".

Routes sorted chronologically by born date instead of tier+frequency.
Removed getGitFrequency(), branch_depth, trace_depth_cap from RouteEntry.
The scanner is now an internal implementation detail. It runs silently
at the start of every /oracle inventory and /oracle stats session.
Users never see raw scan output or /oracle scan as a command.

Merges product health and codebase health into a single /oracle stats
dashboard. Moves --visualize flag to /oracle inventory --visualize.
The scan manifest is read once to build the work queue, then never
referenced during route analysis. Deducting it from budget was consuming
85% of available lines on real projects (7,659-line manifest / 3 = 2,553
of 3,000 budget), leaving zero room for actual route processing.

Only the product map is deducted — Claude actively references it while
writing inventory docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The visualizer (visualize-graph.ts) expects `route` and `branch_files` (array)
fields but scan-imports.ts outputs `path` and `branch_files` (count) +
`co_changed_files` (array). This field mismatch causes the graph to render
with all route IDs as "route:undefined", producing a blank page.

Removing the flag until the scanner/visualizer field contract is aligned.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds /oracle to the skill table and a full deep dive section covering:
- Product conscience philosophy (silent integration)
- The 6 modes (bootstrap, inventory, refresh, update, stats, query)
- How inventory works (budgeted, checkpointed, two-tier docs)
- Silent READ/WRITE resolver integration across 8 skills
- Git co-change classification explanation
- Example output for /oracle and /oracle stats

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Updated feature descriptions and complexity metrics in skills documentation.
Refresh mode silently ignored existing Tier 2 inventory docs, leaving
them orphaned on disk with no Inventory: pointer in the product map.
Add Inventory: field to Tier 1 entry template and schema reference,
reorder checkpoint to write Tier 2 first so the pointer is available,
and add a new "wire inventory docs" step to refresh that discovers
existing docs by F-number prefix.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@rafiulnakib rafiulnakib force-pushed the feat/oracle-scan-inventory branch from a8157cb to 90702b3 Compare March 28, 2026 06:27
Rafiul Nakib and others added 6 commits March 28, 2026 12:50
Inventory docs now go to docs/oracle/inventory/ in the project repo
instead of ~/.gstack/projects/$SLUG/inventory/. This makes them
version-controlled, discoverable by any contributor or Claude session,
and browsable in the repo without needing access to ~/.gstack.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On first inventory run, detects existing Tier 2 docs at the old
~/.gstack/projects/$SLUG/inventory/ location, copies them to
docs/oracle/inventory/ in the project repo, and removes the old dir.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…location

Scanner pipeline was completely non-functional (6/7 modules missing, only
core.ts existed). This builds everything scan-imports.ts needs:

- scanner/routes.ts: framework detection (React Router, Next.js App/Pages)
  + layered route discovery (filesystem, router parsing, Edge Functions)
- scanner/aliases.ts: Vite alias resolution via AST + eval fallback
- scanner/dead-code.ts: unreachable file detection from import graph
- scanner/css.ts: CSS/SCSS import tracking (@import, @use)
- scanner/monorepo.ts: workspace detection (npm, pnpm, lerna)
- scanner/non-ts.ts: non-TypeScript file discovery (30+ extensions)
- scanner/core.ts: generalized findFiles() walker from findTsFiles()
- 7 test fixture directories for all scanner modules
- 6 new tests (84 total pass)
- SKILL.md: PRODUCT_MAP.md relocated from memory dir to docs/oracle/
  as single source of truth (auto-migration for legacy projects)

Verified: scanner produces valid manifest on iskool-prod (536 files, 73K lines).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Scanner was failing in Claude Code's sandboxed shell because bun/node
weren't in PATH. Now compiles to a self-contained binary via
bun build --compile, same pattern as browse/design/gstack-global-discover.

- Add typescript as explicit dependency (used by core.ts, aliases.ts)
- Add scan-imports compile step to build script
- Update SKILL.md to invoke compiled binary directly

Note: run `bun run build` to produce oracle/bin/dist/scan-imports binary,
then `git add oracle/bin/dist/scan-imports` to commit it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@rafiulnakib rafiulnakib marked this pull request as draft March 28, 2026 08:29
- Add /oracle to README install instruction skill lists (Step 1 + Step 2)
- Add oracle/ directory to CLAUDE.md project structure tree
- Update CLAUDE.md compiled binaries section to include oracle/bin/dist/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant