npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mkhitar99/context-pruner

v1.0.1

Published

AST-based codebase pruner for LLM context — strip implementation, keep architecture, reduce tokens by up to 80%

Readme

@mkhitar99/context-pruner

AST-based codebase pruner for LLM context — strip implementation details, keep architecture, reduce tokens by up to 80%.

Philosophy

Give the AI the Skeleton, not the Meat, to maximize reasoning efficiency.

Instead of pasting one file at a time into your LLM chat, prune your entire project into a structured, token-efficient snapshot — with every class, function, and type still visible by signature.


Table of Contents


Features

  • AST Parsing — Uses ts-morph for safe, syntax-aware code transformation
  • Function Body Stripping — Replaces implementations with /* logic */
  • Semantic Pointers — Every definition includes filepath:line for on-demand retrieval
  • Token Budget — Set a target token count; the pruner adjusts aggressively to meet it
  • Depth Map — Configure full, skeleton, or none per directory pattern
  • XML & Markdown — Output formats optimized for LLM consumption
  • gitignore-aware — Respects .gitignore and .prunerignore

Installation

# Global install (recommended for CLI usage)
npm install -g @mkhitar99/context-pruner

# Local install (for programmatic API or npm scripts)
npm install --save-dev @mkhitar99/context-pruner

Quick Start

# 1. Initialize a config file in your project
context-pruner init

# 2. Prune your project (outputs CONTEXT.xml by default)
context-pruner prune

# 3. Paste CONTEXT.xml into Claude, ChatGPT, or any LLM

CLI Reference

init

Generates a pruner.config.json in the current directory with sensible defaults.

context-pruner init

Options:

| Flag | Description | |------|-------------| | --format <xml\|markdown> | Default output format to use in the generated config (default: xml) | | --budget <number> | Default token budget to write into the config (default: 8000) |

Examples:

# Generate default config
context-pruner init

# Generate config pre-set for markdown and a tighter budget
context-pruner init --format markdown --budget 4000

prune

Crawls a directory, parses TypeScript files, and emits a pruned context snapshot.

context-pruner prune [path] [options]

[path] defaults to . (current directory) if omitted.

Options:

| Flag | Alias | Description | Default | |------|-------|-------------|---------| | --format <xml\|markdown> | -f | Output format | xml | | --output <file> | -o | Output file path. Use - for stdout | CONTEXT.xml | | --budget <number> | -b | Target token count. Pruner aggressively strips to meet this | none | | --config <file> | -c | Path to a pruner.config.json config file | none | | --depth <full\|skeleton\|none> | -d | Override depth level for all files (ignores depthMap) | none | | --preserve-types | | Keep all interface, type, and enum declarations even in skeleton mode | false | | --no-pointers | | Omit the pointer index from output | false | | --quiet | -q | Suppress progress output | false |

Examples:

# Prune current directory, default settings (XML to CONTEXT.xml)
context-pruner prune

# Prune a specific subdirectory
context-pruner prune ./src

# Output as Markdown
context-pruner prune ./src --format markdown --output CONTEXT.md

# Enforce a 5000-token budget
context-pruner prune ./src --budget 5000

# Skeleton-only pass on everything (ignore depthMap)
context-pruner prune ./src --depth skeleton

# Use a config file
context-pruner prune . --config pruner.config.json

# Combine: config file + override output path
context-pruner prune . --config pruner.config.json --output MY-CONTEXT.xml

# Print to stdout instead of a file (useful for piping)
context-pruner prune ./src --output -

# Pipe into pbcopy (macOS clipboard)
context-pruner prune ./src --output - | pbcopy

# Keep all types even in skeleton directories
context-pruner prune ./src --depth skeleton --preserve-types

# Quiet mode (no progress logs — good for CI)
context-pruner prune . --quiet --output CONTEXT.xml

Configuration File

Create pruner.config.json in your project root (or generate it with context-pruner init):

{
  "outputFormat": "xml",
  "tokenBudget": 8000,
  "depthMap": {
    "src/core/**": "full",
    "src/utils/**": "skeleton",
    "src/models/**": "full",
    "src/services/**": "skeleton",
    "src/api/**": "skeleton",
    "tests/**": "none",
    "**/*.test.ts": "none",
    "**/*.spec.ts": "none"
  },
  "preserveTypes": true,
  "includeDevDependencies": false
}

All Config Fields

| Field | Type | Description | Default | |-------|------|-------------|---------| | outputFormat | "xml" \| "markdown" | Output format | "xml" | | tokenBudget | number | Target token count | none | | depthMap | Record<string, "full" \| "skeleton" \| "none"> | Glob-pattern-to-depth mapping. Evaluated top-to-bottom; first match wins | {} | | preserveTypes | boolean | Preserve all type declarations even in skeleton files | false | | includeDevDependencies | boolean | Include devDependencies in output | false |

Glob matching uses standard glob patterns (**, *, ?). Patterns are matched against the file path relative to the pruned root.


Depth Levels

| Level | What is kept | What is stripped | |-------|-------------|-----------------| | full | Everything — complete source | Nothing | | skeleton | Signatures, types, interfaces, constants, exports | Function bodies, method bodies, private variable initializers | | none | Nothing | The entire file is excluded from output |

skeleton mode preserves:

  • Function and method signatures (name, parameters, return type)
  • Class declarations and their member signatures
  • interface, type, and enum declarations
  • Exported constants and their values
  • Import statements
  • JSDoc comments above declarations

skeleton mode strips:

  • Function and method bodies → replaced with /* logic */
  • Private variable assignments
  • Inline comments inside bodies

Output Formats

XML (default)

Structured and easy for LLMs to parse. Recommended for most use cases.

<?xml version="1.0" encoding="UTF-8"?>
<context tokenBudget="8000">
  <pointers>
    <pointer file="src/auth.ts" line="12" symbol="AuthService" />
    <pointer file="src/auth.ts" line="20" symbol="AuthService.login" />
    <pointer file="src/auth.ts" line="85" symbol="withAuth" />
  </pointers>

  <file path="src/auth.ts">
    <![CDATA[
    export class AuthService {
      constructor(db: DatabaseClient, config: AuthConfig) { /* logic */ }
      async login(email: string, password: string): Promise<AuthToken> { /* logic */ }
      async register(email: string, password: string, name: string): Promise<User> { /* logic */ }
      private generateToken(user: User): AuthToken { /* logic */ }
    }

    export function withAuth<T>(
      handler: (user: User, ...args: any[]) => Promise<T>,
      requiredPermission?: Permission
    ): (...args: any[]) => Promise<T> { /* logic */ }
    ]]>
  </file>
</context>

Markdown

Readable in any editor or Markdown viewer. Good for pasting into chat UIs.

## Pointer Index
- `AuthService` — src/auth.ts:12
- `AuthService.login` — src/auth.ts:20
- `withAuth` — src/auth.ts:85

## src/auth.ts
```typescript
export class AuthService {
  constructor(db: DatabaseClient, config: AuthConfig) { /* logic */ }
  async login(email: string, password: string): Promise<AuthToken> { /* logic */ }
}

---

## Programmatic API

```typescript
import { prune, PruneOptions } from '@mkhitar99/context-pruner';

const output = await prune('./my-project', {
  outputFormat: 'markdown',
  tokenBudget: 5000,
  depthMap: {
    'src/core/**': 'full',
    'src/utils/**': 'skeleton',
    'tests/**': 'none',
  },
  preserveTypes: true,
});

console.log(output);

prune(rootPath, options?)

| Parameter | Type | Description | |-----------|------|-------------| | rootPath | string | Absolute or relative path to the directory to prune | | options | PruneOptions | Optional. Same fields as pruner.config.json |

Returns: Promise<string> — the full pruned output as a string (XML or Markdown).

PruneOptions

interface PruneOptions {
  outputFormat?: 'xml' | 'markdown';
  tokenBudget?: number;
  depthMap?: Record<string, 'full' | 'skeleton' | 'none'>;
  preserveTypes?: boolean;
  includeDevDependencies?: boolean;
  noPointers?: boolean;
}

Ignore Files

context-pruner respects two ignore files:

.gitignore

Standard .gitignore rules. Files ignored by git are automatically excluded.

.prunerignore

Same syntax as .gitignore, but pruner-specific. Use this to exclude files from the pruned output that you still want tracked by git.

# .prunerignore example

# Exclude generated output files from being pruned recursively
CONTEXT*.xml
CONTEXT*.md

# Exclude CI config — not useful for LLM context
.github/

# Exclude lock files
package-lock.json
yarn.lock

# Exclude compiled output
dist/
*.d.ts

Precedence: .prunerignore rules are applied after .gitignore. A file excluded by either will not appear in output.


How It Works

Your project
     │
     ▼
1. Discovery ──────── Crawls directory tree, applies .gitignore + .prunerignore
     │
     ▼
2. AST Decomposition ─ Parses each .ts file into an Abstract Syntax Tree via ts-morph
     │
     ▼
3. Depth Resolution ── Matches each file path against depthMap globs (first match wins)
     │
     ▼
4. Pruning ─────────── Strips function bodies / excludes files based on resolved depth
     │
     ▼
5. Token Accounting ── Counts tokens across all files; if over budget, re-prunes aggressively
     │
     ▼
6. Serialization ───── Re-serializes AST nodes into XML or Markdown
     │
     ▼
7. Pointer Injection ─ Prepends filepath:line index for every class, function, interface, enum
     │
     ▼
Output file (CONTEXT.xml / CONTEXT.md)

Examples

Minimal — just dump the architecture

context-pruner prune ./src --depth skeleton --output CONTEXT.md

Full project with per-directory control

context-pruner prune . --config pruner.config.json --output CONTEXT.xml

Tight token budget for small context windows

context-pruner prune ./src --budget 3000 --format xml --output CONTEXT-small.xml

Copy directly to clipboard (macOS)

context-pruner prune ./src --format markdown --output - | pbcopy

Copy directly to clipboard (Linux)

context-pruner prune ./src --format markdown --output - | xclip -selection clipboard

Use in an npm script

{
  "scripts": {
    "context": "context-pruner prune . --config pruner.config.json --output CONTEXT.xml",
    "context:md": "context-pruner prune . --format markdown --output CONTEXT.md",
    "context:small": "context-pruner prune ./src --budget 4000 --output CONTEXT-small.xml"
  }
}

Use in GitHub Actions (generate context snapshot on push)

name: Generate Context
on:
  push:
    branches: [main]

jobs:
  context:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm install -g @mkhitar99/context-pruner
      - run: context-pruner prune . --config pruner.config.json --output CONTEXT.xml
      - uses: actions/upload-artifact@v4
        with:
          name: context-snapshot
          path: CONTEXT.xml

Programmatic usage in a build script

import { prune } from '@mkhitar99/context-pruner';
import { writeFileSync } from 'fs';

async function generateContext() {
  const output = await prune('./src', {
    outputFormat: 'xml',
    tokenBudget: 8000,
    depthMap: {
      'src/core/**': 'full',
      'src/utils/**': 'skeleton',
      'tests/**': 'none',
    },
    preserveTypes: true,
  });

  writeFileSync('CONTEXT.xml', output, 'utf-8');
  console.log('Context snapshot written to CONTEXT.xml');
}

generateContext();

Changelog

1.0.0

  • Initial release
  • AST parsing with ts-morph
  • Function body stripping with /* logic */ placeholders
  • Semantic pointer generation (filepath:line)
  • Configurable depth map (full / skeleton / none)
  • Token budget enforcement
  • XML and Markdown output serialization
  • .gitignore and .prunerignore support

License

MIT