Skip to main content

Pure RAM, per-skill, declarative in-memory indexing framework for AI skill authors

Project description

vapor-idx

Pure RAM. Per-skill. Gone when you're done.

vapor-idx is a zero-dependency, fully declarative, in-memory indexing framework for AI skill authors. It gives individual skills a structured, queryable, traversable knowledge store that lives entirely in process memory and disappears the moment the skill ends — no files, no databases, no persistence, no cross-skill leakage.

It is RAM — shaped, named, and queryable — scoped to exactly one skill invocation at a time.

GitHub: https://github.com/RebornBeat/vapor-idx Discord: https://discord.gg/vapor-idx


Why does this exist?

When you write a Claude skill that needs to reason over structured data — a code analysis skill that must track function relationships, a document skill that must link sections to their references, an image skill that must index pixels spatially, a 3D skill that must traverse mesh topology — you need somewhere to put that structure while the skill runs. Without a tool like this, every skill author re-implements ad-hoc Maps, arrays of objects, and linear scans.

vapor-idx provides the scaffold so skill authors declare their data model once and query it cleanly, without reinventing indexing primitives every time.

What it is not:

  • It does not persist anything. Ever. By design.
  • It does not share state between skills.
  • It does not use embeddings, ML models, or vector search.
  • It does not have defaults. Every type, field, and index strategy is declared explicitly by the skill author.
  • It does not enforce opinions about your data shape.

vapor.store(type, data) stores in RAM. Records live as JavaScript objects, Python dicts, and Rust structs — inside the running process, held in working memory, gone when the skill ends. Nothing is written to disk unless the skill author explicitly chooses to serialise a snapshot themselves.


The broader vision: modality-first indexing

vapor-idx is not limited to traditional structured data. Because it indexes any declared schema into RAM relationships, it can decompose and traverse any modality that can be expressed as typed records with connections.

Images without ML dependencies

Instead of YOLO, ResNet, or any external model, declare a Pixel type and index every pixel by position and colour. Traverse adjacency relationships. Claude — acting as the zero-shot intelligence within the skill — applies its own semantic reasoning over the structured index to identify regions, edges, and objects. Reconstruct from the indexed structure back to a .png file, an SVG, or a CSS layout — no ML dependency, no external model call, pure RAM.

const vapor = createVapor({
  types: {
    Pixel: {
      fields: {
        x:         { type: 'number', index: 'range' },
        y:         { type: 'number', index: 'range' },
        r:         { type: 'number', index: 'range' },
        g:         { type: 'number', index: 'range' },
        b:         { type: 'number', index: 'range' },
        edgeScore: { type: 'number', index: 'range' },
        region:    { type: 'string', index: 'exact'  },
      },
      relationships: {
        ADJACENT_TO: { targetTypes: ['Pixel'],  directed: false, cardinality: 'many-to-many' },
        BELONGS_TO:  { targetTypes: ['Region'], directed: true,  cardinality: 'many-to-one'  },
      },
    },
    Region: {
      fields: {
        label:   { type: 'string', index: 'keyword' },
        area:    { type: 'number', index: 'range'   },
        centerX: { type: 'number', index: 'range'   },
        centerY: { type: 'number', index: 'range'   },
      },
    },
  },
});

3D mesh without a render engine

Index every vertex, edge, face, and material from an OBJ/STL/GLTF as typed records with spatial relationships. Traverse mesh topology. Emit a Blender Python script that reconstructs the full .blend file, or reconstruct a clean OBJ — from indexed structure alone. No rendering engine required during analysis. The full Blender API surface can be reconstructed from indexed data, including armatures, physics, materials, animations, and modifiers — all as pure Python.

const vapor = createVapor({
  types: {
    Vertex: {
      fields: {
        x:             { type: 'number', index: 'range' },
        y:             { type: 'number', index: 'range' },
        z:             { type: 'number', index: 'range' },
        normalX:       { type: 'number', index: 'none'  },
        normalY:       { type: 'number', index: 'none'  },
        normalZ:       { type: 'number', index: 'none'  },
        materialIndex: { type: 'number', index: 'exact' },
      },
      relationships: {
        CONNECTED_TO: { targetTypes: ['Vertex'], directed: false, cardinality: 'many-to-many' },
        PART_OF:      { targetTypes: ['Face'],   directed: true,  cardinality: 'many-to-many' },
      },
    },
    Face: {
      fields: {
        materialIndex: { type: 'number', index: 'exact' },
        area:          { type: 'number', index: 'range' },
        smoothGroup:   { type: 'number', index: 'exact' },
      },
      relationships: {},
    },
    Material: {
      fields: {
        name:      { type: 'string', index: 'exact' },
        roughness: { type: 'number', index: 'range' },
        metallic:  { type: 'number', index: 'range' },
        baseColorR:{ type: 'number', index: 'range' },
        baseColorG:{ type: 'number', index: 'range' },
        baseColorB:{ type: 'number', index: 'range' },
      },
      relationships: {},
    },
  },
});

Cross-modal reconstruction

Index elements from one modality, traverse semantically, and reconstruct in another. An indexed SVG design becomes a CSS layout. An indexed audio waveform becomes a MIDI file. An indexed set of pixels becomes a vector graphic. An indexed 3D mesh becomes a Blender Python script. Claude traverses the relationships and drives the reconstruction — the index is the bridge, not any ML model.

This works because Claude is the zero-shot intelligence when a skill runs. vapor-idx provides the structure; Claude provides the reasoning. Together they enable modality understanding and reconstruction without any external model calls.


Monorepo structure

Skills execute in multiple runtimes. A single npm package cannot serve a Python computer-use skill, and a Python package cannot serve a browser artifact. Each package is a faithful implementation of the same API contract in its target language.

vapor-idx/
├── README.md
├── TESTING.md                         ← deploy + test guide
├── DOCS/
│   ├── CONCEPT.md
│   ├── API_REFERENCE.md
│   ├── PIXEL_INDEXING.md
│   ├── 3D_INDEXING.md
│   └── CROSS_MODAL.md
├── skills/
│   ├── pixel-analyzer/SKILL.md
│   ├── mesh-analyzer/SKILL.md
│   ├── design-indexer/SKILL.md
│   └── cross-modal-reconstructor/SKILL.md
└── packages/
    ├── vapor-idx/                     ← TypeScript / JavaScript (Node.js + Browser ESM)
    │   ├── package.json
    │   ├── tsconfig.json
    │   └── src/
    │       ├── index.ts
    │       ├── types.ts
    │       ├── VaporInstance.ts
    │       ├── SchemaValidator.ts
    │       ├── RecordStore.ts
    │       ├── RelationshipStore.ts
    │       ├── QueryEngine.ts
    │       ├── TraversalEngine.ts
    │       └── indexes/
    │           ├── ExactIndex.ts
    │           ├── KeywordIndex.ts
    │           ├── PrefixIndex.ts
    │           └── RangeIndex.ts
    │
    ├── vapor-idx-py/                  ← Python 3.10+ (PyPI)
    │   ├── pyproject.toml
    │   └── vapor_idx/
    │       ├── __init__.py
    │       ├── types.py
    │       ├── instance.py
    │       ├── schema.py
    │       ├── record_store.py
    │       ├── relationship_store.py
    │       ├── query_engine.py
    │       ├── traversal_engine.py
    │       └── indexes/
    │           ├── __init__.py
    │           ├── exact.py
    │           ├── keyword.py
    │           ├── prefix.py
    │           └── range_.py
    │
    └── vapor-idx-rs/                  ← Rust (crates.io)
        ├── Cargo.toml
        └── src/
            ├── lib.rs
            ├── types.rs
            ├── instance.rs
            ├── schema.rs
            ├── record_store.rs
            ├── relationship_store.rs
            ├── query_engine.rs
            ├── traversal_engine.rs
            └── indexes/
                ├── mod.rs
                ├── exact.rs
                ├── keyword.rs
                ├── prefix.rs
                └── range.rs

Which runtime should I use?

Environment Runtime Install
Claude Code / Node.js skill scripts Node.js npm install vapor-idx
Claude web Artifacts (browser ESM) Browser CDN or bundled ESM
Claude computer-use (Python) Python 3.10+ pip install vapor-idx
Rust-based skill tooling Rust cargo add vapor-idx

Installation

Node.js / Browser (TypeScript / JavaScript)

npm install vapor-idx

Browser ESM (no build step)

<script type="module">
  import { createVapor } from 'https://esm.sh/vapor-idx';
</script>

Python

pip install vapor-idx

Rust

[dependencies]
vapor-idx = "0.1"

Core concepts

Schema-first, no defaults

You declare every type, every field, and the index strategy for every field before storing a single record. There are no auto-detected types, no implicit indexes, no convenience defaults. The schema is the law of your skill's index.

Index strategies

Strategy What it indexes Supported operations
none Nothing — stored only Retrieval by ID only
exact Exact value equality eq, neq, in, notIn
keyword Tokenised inverted index contains, free-text keywords
prefix Trie-based prefix matching startsWith
range Sorted numeric values gt, lt, gte, lte

Range indexes correctly handle negative numbers, zero, and positive numbers across all three language implementations.

Records are RAM variables

vapor.store(type, data) returns a string ID and holds the record in process memory as a native language value — a JavaScript object, a Python frozen dataclass, a Rust struct. Nothing touches the filesystem. Records disappear when the instance is destroyed or the process ends.

Relationships

Types can declare named relationship kinds between them. Relationships are directional or bidirectional, with declared cardinality (one-to-one, one-to-many, many-to-many). They are stored as first-class edges traversable by the query and traversal engines.

Traversal

The traversal engine follows relationship edges from a starting node using BFS, up to a declared depth, with optional filtering applied at each hop. It returns both the matched records and the full path metadata.

Snapshots

At any point you can take a snapshot of the entire index state as a plain serialisable value. Snapshots are RAM-only — serialisation to disk is the caller's responsibility.


Quick start — TypeScript

import { createVapor } from 'vapor-idx';

const vapor = createVapor({
  types: {
    Function: {
      fields: {
        name:       { type: 'string',   index: 'exact'   },
        filePath:   { type: 'string',   index: 'exact'   },
        docstring:  { type: 'string',   index: 'keyword' },
        lineStart:  { type: 'number',   index: 'range'   },
        lineEnd:    { type: 'number',   index: 'range'   },
        isAsync:    { type: 'boolean',  index: 'exact'   },
        tags:       { type: 'string[]', index: 'keyword' },
        visibility: { type: 'string',   index: 'prefix'  },
      },
      relationships: {
        CALLS: {
          targetTypes:  ['Function'],
          directed:     true,
          cardinality:  'many-to-many',
        },
        DEFINED_IN: {
          targetTypes:  ['Module'],
          directed:     true,
          cardinality:  'many-to-one',
        },
      },
    },
    Module: {
      fields: {
        path:     { type: 'string', index: 'exact'   },
        language: { type: 'string', index: 'exact'   },
        summary:  { type: 'string', index: 'keyword' },
      },
    },
  },
});

const modId = vapor.store('Module', {
  path:     'src/parser.ts',
  language: 'typescript',
  summary:  'Parses AST nodes and extracts function signatures',
});

const fnId = vapor.store('Function', {
  name:       'parseFunction',
  filePath:   'src/parser.ts',
  docstring:  'Extracts function name, parameters, and return type from an AST node',
  lineStart:  42,
  lineEnd:    78,
  isAsync:    false,
  tags:       ['parsing', 'ast', 'extraction'],
  visibility: 'public',
});

vapor.relate(fnId, 'DEFINED_IN', modId);

const asyncFns = vapor.query({
  type:  'Function',
  where: { field: 'isAsync', op: 'eq', value: true },
});

const parsingFns = vapor.query({
  type:     'Function',
  keywords: 'ast extraction',
});

const largeFns = vapor.query({
  type:    'Function',
  where:   { field: 'lineEnd', op: 'gt', value: 100 },
  orderBy: { field: 'lineStart', direction: 'asc' },
  limit:   10,
});

const callChain = vapor.traverse({
  from:         fnId,
  relationship: 'CALLS',
  direction:    'outgoing',
  depth:        3,
});

console.log(vapor.stats());

const snap = vapor.snapshot();
const fork = vapor.restore(snap);

vapor.destroy();

Quick start — Python

from vapor_idx import create_vapor, QueryOptions, FieldFilter, TraversalOptions, PathOptions

vapor = create_vapor({
    "types": {
        "Function": {
            "fields": {
                "name":       {"type": "string",   "index": "exact"},
                "file_path":  {"type": "string",   "index": "exact"},
                "docstring":  {"type": "string",   "index": "keyword"},
                "line_start": {"type": "number",   "index": "range"},
                "is_async":   {"type": "boolean",  "index": "exact"},
                "tags":       {"type": "string[]", "index": "keyword"},
            },
            "relationships": {
                "CALLS": {
                    "targetTypes": ["Function"],
                    "directed":    True,
                    "cardinality": "many-to-many",
                },
            },
        },
    },
})

fn_id = vapor.store("Function", {
    "name":       "parse_function",
    "file_path":  "parser.py",
    "docstring":  "Extracts function signatures from AST nodes",
    "line_start": 42,
    "is_async":   False,
    "tags":       ["parsing", "ast"],
})

results = vapor.query(QueryOptions(
    type="Function",
    keywords="ast extraction",
))

print(vapor.stats())
vapor.destroy()

Quick start — Rust

use vapor_idx::{
    create_vapor, VaporSchema, TypeDefinition, FieldDefinition,
    FieldType, IndexStrategy, QueryOptions, FieldFilter, FilterOp,
};
use std::collections::HashMap;

fn main() {
    // VaporSchema is a plain struct — initialise with struct literal
    let schema = VaporSchema {
        types: HashMap::from([
            ("Function".to_string(), TypeDefinition {
                fields: HashMap::from([
                    ("name".to_string(), FieldDefinition {
                        field_type: FieldType::String,
                        index:      IndexStrategy::Exact,
                        required:   true,
                    }),
                    ("line_start".to_string(), FieldDefinition {
                        field_type: FieldType::Number,
                        index:      IndexStrategy::Range,
                        required:   true,
                    }),
                ]),
                relationships: HashMap::new(),
            }),
        ]),
    };

    // create_vapor returns VaporResult<VaporInstance>
    let mut vapor = create_vapor(schema).expect("valid schema");

    let fn_id = vapor.store(
        "Function",
        serde_json::json!({ "name": "parse_function", "line_start": 42 }),
    ).unwrap();

    let results = vapor.query(&QueryOptions {
        type_filter: Some(vec!["Function".to_string()]),
        where_filters: vec![FieldFilter {
            field: "line_start".to_string(),
            op:    FilterOp::Gt,
            value: serde_json::json!(10),
        }],
        ..Default::default()
    }).unwrap();

    println!("Found {} results", results.total);
    vapor.destroy();
}

API reference

createVapor(schema) / create_vapor(schema)VaporInstance

Creates a new isolated index bound to the provided schema. Validates the schema at construction time. No types, fields, or relationships exist until declared. In Rust, returns VaporResult<VaporInstance>.


vapor.store(type, data)string (record ID)

Stores a record of the given type in RAM as a native language object. Returns a generated ID (vpr_<timestamp>_<counter>). Throws if the type is not declared or required fields are missing.


vapor.get(id)VaporRecord | null

Returns a single record by ID. O(1) lookup from a HashMap/dict/Map.


vapor.update(id, partial)void

Updates fields on an existing record. Re-indexes all changed fields.


vapor.delete(id)void

Removes a record and all its relationship edges from the index.


vapor.relate(sourceId, relType, targetId, metadata?)string (edge ID)

Creates a relationship edge. Validates both records exist, the relationship type is declared, and the target type is permitted. Bidirectional relationships create edges in both directions automatically.


vapor.unrelate(edgeId)void

Removes a relationship edge by edge ID.


vapor.query(options)QueryResult

Executes a query against the index.

interface QueryOptions {
  type?:     string | string[];           // restrict by type
  where?:    FieldFilter | FieldFilter[]; // field-level predicates
  keywords?: string | string[];           // free-text across keyword fields
  logic?:    'AND' | 'OR';               // how multiple where clauses combine
  limit?:    number;
  offset?:   number;
  orderBy?:  { field: string; direction: 'asc' | 'desc' };
}

Operators by index strategy:

Strategy Valid operators
exact eq, neq, in, notIn
keyword contains
prefix startsWith
range gt, lt, gte, lte
none not directly queryable

vapor.traverse(options)TraversalResult

BFS traversal following relationship edges from a starting node.

interface TraversalOptions {
  from:         string;
  relationship: string;
  direction?:   'outgoing' | 'incoming' | 'both';
  depth?:       number;
  filter?:      Omit<QueryOptions, 'limit' | 'offset' | 'orderBy'>;
}

vapor.findPath(options)string[] | null

Returns the shortest ID path between two records, or null if no path exists within maxDepth.


vapor.getRelationships(id, type?, direction?)VaporRelationship[]

Returns all relationship edges for a given record, optionally filtered.


vapor.stats()VaporStats

Returns record counts by type, relationship counts by type, index sizes, and a rough memory estimate in bytes.


vapor.snapshot()VaporSnapshot

Captures the full current state as a plain serialisable object. RAM only.


vapor.restore(snapshot)VaporInstance

Returns a new VaporInstance hydrated from a snapshot. Schema hashes must match.


vapor.destroy()void

Releases all references. Safe to call multiple times.


Skill authoring guidelines

Declare only what you need. Memory scales with index type and cardinality.

For spatial/pixel/vertex data, always use range on coordinate fields. Range queries (gt/lt/gte/lte) are the foundation of spatial understanding. All three implementations correctly handle negative coordinates and zero.

Let Claude traverse — Claude is the zero-shot intelligence. vapor-idx provides structure; Claude provides semantic reasoning. A skill does not need an external ML model to understand modality relationships — it indexes the data and lets Claude traverse and interpret.

Destroy explicitly. Call vapor.destroy() when done to release memory promptly rather than waiting for scope exit or GC.

Use snapshots for branching logic. Snapshot before exploring an interpretation; restore the losing branch.

Do not pass instances across skill boundaries. Each skill creates its own instance from its own schema.


Philosophy

vapor-idx is deliberately minimal. It does not implement:

  • Embeddings or vector similarity
  • ML-guided ranking or confidence scoring
  • Persistence to any storage medium
  • Cross-skill or cross-session state
  • Schema migrations
  • Query optimiser hints
  • Transactions or rollback

These are intentional exclusions. The moment you need any of them, you have outgrown an in-skill ephemeral index and you need a real database.

What vapor-idx does is provide a clean, consistent, language-agnostic API for declaring structured knowledge in RAM and querying it with zero dependencies. Combined with Claude's own reasoning, this is sufficient to analyse, reconstruct, and transform any modality that can be expressed as typed records with connections.


Package publishing

Package Registry Import
vapor-idx npm import { createVapor } from 'vapor-idx'
vapor-idx PyPI from vapor_idx import create_vapor
vapor-idx crates.io use vapor_idx::create_vapor;

All three packages are versioned in lockstep.


Documentation

Skills


License

MIT

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

vapor_idx-0.1.0.tar.gz (21.3 kB view details)

Uploaded Source

Built Distribution

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

vapor_idx-0.1.0-py3-none-any.whl (25.1 kB view details)

Uploaded Python 3

File details

Details for the file vapor_idx-0.1.0.tar.gz.

File metadata

  • Download URL: vapor_idx-0.1.0.tar.gz
  • Upload date:
  • Size: 21.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for vapor_idx-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c0b54159d5c29eb8803074cc1ac4f742232fbb1577c123b0b321875446b6d1ba
MD5 019fbfe556f3e124f118ccf6af883a5c
BLAKE2b-256 3171f325090db9e5a0889c9faa27617d13fae36276f4e4beaf95311301be4a50

See more details on using hashes here.

File details

Details for the file vapor_idx-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: vapor_idx-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 25.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for vapor_idx-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2d5cbd2b3dfccb4d5c5163d517dad9fc1ca6cd2ec6a4c5eb744019f6cd88f879
MD5 4896c0de7ad046248e350a0ef513c58d
BLAKE2b-256 12f886cc9468f6a01088c41d2cf5a611bc69821d82b0526f414a1e42f54243a2

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