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.1.tar.gz (24.4 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.1-py3-none-any.whl (28.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: vapor_idx-0.1.1.tar.gz
  • Upload date:
  • Size: 24.4 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.1.tar.gz
Algorithm Hash digest
SHA256 1b841439c75c5984f768713cd9f0abc25b1701e5f3676dac0df77746197d0747
MD5 e53bf4c610b9002908a7af5e074a5bb9
BLAKE2b-256 ff728cb5cdfc324d67c750e1bfe48a74506f66a5d3ded33766302851b53a1dec

See more details on using hashes here.

File details

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

File metadata

  • Download URL: vapor_idx-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 28.8 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 06eddfc911152333957fe7a9e7d9fe41604e9db5c93c71319dfe2079eda14512
MD5 d4ba2d23ba9fd8928669a655031e9e57
BLAKE2b-256 fe9d52d1b549a9c490559b970ec6a1e59dc38c3f46bc0e3bb8ceca9b7e3b38ba

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