Skip to main content

CLI shell for VLMX

Project description

vlmx-sh

A terminal DSL shell for entrepreneurs — graph-based company data management through a natural language command interface.

Overview

vlmx-sh is a Textual-based TUI application that lets you manage structured company data using a simple shell-like DSL. Organisations and their data live in SQLite databases; navigation mirrors a filesystem hierarchy (cd, ~, ..).

Features

  • Context-aware navigation — move between system, org, and app levels with cd
  • Natural language DSL — commands like add brand vision="We change the world"
  • Graph data model — nodes (companies, people, brands, …) and edges stored in SQLite
  • Per-org databases — each organisation gets its own isolated .db file
  • Textual UI — keyboard-driven terminal interface with org list sidebar

Requirements

  • Python 3.11+
  • uv

Installation

git clone <repo-url>
cd vlmx-sh
uv sync

Running

# Via the installed script
vlmx

# Or directly
python -m vlmx_sh

DSL Commands

All commands follow the pattern: <verb> [target] [field=value ...]

Navigation

Command Description
cd acme Enter the acme org context
cd .. Go up one level
cd ~ Return to system root

Org management

Command Description
create company:Acme Create a new company and enter it
drop company:Acme Permanently delete a company
show company List all companies

Data management (inside an org context)

Command Description
add brand vision="..." mission="..." Set brand fields (singleton)
add person:Alice role="CEO" Add a named person node
show brand Show all brand fields
show brand vision mission Show specific fields
show person List all persons
edit person:Alice role="CTO" Update a named node
delete brand vision Clear a specific field
delete brand Clear all brand fields
delete person:Alice Soft-delete a named node

Keyboard shortcuts

Key Action
d Toggle dark / light mode

Architecture

src/vlmx_sh/
├── core/
│   ├── enums/          # OrgType, Legal, Currency, ContextLevel, TokenType, …
│   ├── models/         # Context, Word hierarchy, ValidationContext, responses
│   ├── nodes/          # BaseNode, org nodes, item nodes, meta nodes
│   └── registry.py     # Maps node classes ↔ DSL words
├── dsl/
│   ├── parser/         # 7-stage parsing pipeline (see below)
│   ├── ir/             # IRCommand — stable intermediate representation
│   ├── ast/            # FilterExpression
│   └── words/          # Verb registrations and macros
├── engine/
│   ├── executor.py     # Single UI entry point: text → parse → IR → dispatch
│   ├── router.py       # Dispatches action_id to registered handlers
│   └── handlers/       # crud.py (add/show/edit/delete), navigation.py (cd)
├── db/
│   ├── sqlite_backend.py  # Per-org SQLite (nodes + edges tables)
│   ├── org_backend.py     # create_org / drop_org lifecycle
│   └── paths.py           # Data directory helpers
├── storage/
│   └── org_registry.py    # org_registry.toml read/write (org name → db path)
└── ui/
    ├── app.py              # Textual App
    ├── screens/main/       # MainScreen (sidebar + command blocks)
    ├── widgets/            # CommandBlock (prompt + input + output)
    ├── formatters/         # Result → display text
    └── styles/design.tcss  # UI styles

Parsing pipeline

Input text goes through seven sequential stages before becoming an IRCommand:

raw text
  → 0. Normalizer    — whitespace cleanup
  → 1. Tokenizer     — split into Token objects (handles quoted strings, operators)
  → 2. Classifier    — assign structural class (TEXT, OPERATOR, BRACKET)
  → 3. Recognizer    — match tokens to registry words (Verb, FieldWord, ItemWord, …)
  → 4. Interpreter   — typo correction, infer missing verb/entity in ORG context
  → 5. Splitter      — separate command tokens from filter tokens
  → 6. Filter parser — build FilterExpression from filter tokens
  → IRCommand        — stable, serialisable command object

Data model

Two fixed SQLite tables per org:

nodes  (id, org_id, type, name, deprecated, created_at, updated_at, properties)
edges  (id, org_id, from_id, to_id, type, created_at, properties)

Type-specific fields are packed into the properties JSON column. Pydantic models on the app layer unpack them transparently via to_storage_dict() / from_storage_dict().

Node types

Org nodes — created at system level via create

type class
company CompanyNode
fund FundNode
foundation FoundationNode
subsidiary SubsidiaryNode

Item nodes — created inside an org context via add

type singleton description
brand yes Vision, mission, values
address yes Physical address
market yes Market data
finance yes Financial data
values yes Company values
metadata yes Arbitrary metadata
person no Team members
offering no Products / services
competitor no Competitor entries
news no News items
portfolio no Portfolio entries
target no Strategic targets

Meta nodes

type description
group Node grouping
tag Tagging

Singleton nodes are upserted (one per org); non-singleton nodes create a new record each time (identified by name).

Context levels

SYS  (~)             — system root; create / list orgs
ORG  (~/acme)        — inside an org; manage all item nodes
APP  (~/acme/app)    — inside an app (future)

The Context object is immutable. Navigation produces a new Context instance.

Data storage layout

data/
├── org_registry.toml          # All known orgs (id, name, db_path, created_at)
├── acme/
│   └── acme.db            # Org database (nodes + edges)
└── valmetrics/
    └── valmetrics.db

Development

# Run tests
uv run pytest tests/

# Run with Textual dev tools (live reload)
uv run textual run --dev src/vlmx_sh/__main__.py

Key design decisions

  • No ORM — plain sqlite3 for portability; codebase may be rewritten in Rust later
  • Two fixed tables — schema never changes; all typed fields live in the properties blob
  • Layered importsnodes/ must not import from models/; models/ may import from nodes/
  • Immutable contextContext is a frozen Pydantic model; navigation returns new instances
  • Registry-driven DSL — words are auto-generated from node classes; verbs are registered manually
  • IR boundary — the engine never sees parser internals; only IRCommand (plain data) crosses the boundary

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

vlmx_sh-0.0.2.tar.gz (47.7 kB view details)

Uploaded Source

Built Distribution

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

vlmx_sh-0.0.2-py3-none-any.whl (71.6 kB view details)

Uploaded Python 3

File details

Details for the file vlmx_sh-0.0.2.tar.gz.

File metadata

  • Download URL: vlmx_sh-0.0.2.tar.gz
  • Upload date:
  • Size: 47.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for vlmx_sh-0.0.2.tar.gz
Algorithm Hash digest
SHA256 9c28a2bba589499de149eb9038632cce9997c893d5b47eff45881de0eaab3aa8
MD5 c0fcbc0f050c23750877c684b7f74192
BLAKE2b-256 65860a4f7bf395ecb96503f105d16ad37ed27548d156001cd0d660628aa7e6f2

See more details on using hashes here.

File details

Details for the file vlmx_sh-0.0.2-py3-none-any.whl.

File metadata

  • Download URL: vlmx_sh-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 71.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for vlmx_sh-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 5ac5cffa1d0253520290db9e2b5f8191fdceb5d2fab6ac31e9b30518a7aa1750
MD5 2ea2247f7f444210e6a240f304446988
BLAKE2b-256 37f84d0b2a29e2eb0d72b6be30c7ad6bc36cccc9f88fceecff4a4c14ad198c3e

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