Skip to main content
Glama
newgepard

opensheet

by newgepard

OpenSheet

Una interfaz de base de datos sin la base de datos.

Tus tablas son archivos .jsonl simples en el disco. Edita una celda — git diff muestra una sola línea. Cierra OpenSheet, y jq, DuckDB, Excel, pandas y tus agentes de IA aún pueden leer todo.

Licencia: MIT Dependencias de ejecución: 0 Pruebas: 329 Llamadas de red: 0

中文文档


Qué es esto

Las herramientas de hoja de cálculo y base de datos tienen que poner tus filas en algún lugar. Las respuestas habituales son una base de datos que también tienes que ejecutar, un motor de almacenamiento que viene con la aplicación, o un único archivo binario en el formato propio de la aplicación. Las tres funcionan. Las tres significan que la herramienta se interpone entre tú y tus datos.

La fuente de verdad de OpenSheet es un archivo de texto que ya sabes leer. Una carpeta es una biblioteca, cada .jsonl dentro es una tabla, una línea es un registro. No hay base de datos, ni cuenta, ni servidor, ni sincronización. Borra OpenSheet y tus datos no se mueven ni un centímetro.

$ cat my-library/campaigns.jsonl
{"id":"KS-001","project":"Modular Mechanical Keyboard","raised_usd":412870,"rating":5}
{"id":"KS-002","project":"Solar Camp Lantern","raised_usd":88250,"rating":4}

$ jq -r 'select(.rating == 5) | .project' my-library/campaigns.jsonl
Modular Mechanical Keyboard

Ese es todo el formato de almacenamiento. La interfaz de hoja de cálculo es una vista sobre él, no un envoltorio.

Related MCP server: jsony-mcp

Inicio rápido

Requiere Python 3.9+. Sin pip install, sin Docker, sin paso de compilación.

git clone https://github.com/newgepard/opensheet
cd opensheet
PYTHONPATH=src python3 -m opensheet ~/my-library/

Abre http://127.0.0.1:<puerto libre> en tu navegador. Apúntalo a una carpeta de archivos .jsonl, a un único archivo .jsonl, o a una carpeta vacía para empezar desde cero.

Aplicación de escritorio para macOS — un shell nativo de 860 KB (Swift + WKWebView, usa el WebKit del sistema):

bash shell/build.sh
open shell/build/OpenSheet.app

La promesa de fidelidad

Esto es sobre lo que se construye todo lo demás, y está probado en lugar de afirmado.

1. Las filas no tocadas se escriben de vuelta byte por byte. Edita una celda en una tabla de 10,000 filas y git diff muestra exactamente una línea cambiada. Las filas que no tocaste nunca se re-serializan — ni se reordenan, ni se reformatean, ni se re-escapan.

2. El texto no ASCII nunca se escapa. {"名前":"甲"} permanece exactamente así. Nunca se convierte en {"\u540d\u524d":"\u7532"}, que es lo que hace json.dumps por defecto y lo que hace que un archivo sea ilegible en cualquier herramienta que no sea un parser JSON.

3. Los archivos dispersos permanecen dispersos. Si una fila no tiene una clave, OpenSheet no la inventará. Añadir un campo a una tabla con 50,000 filas existentes reescribe cero de ellas.

Deshacer está construido como comandos inversos, no como restauración de instantáneas, específicamente para que la promesa 1 sobreviva: edita una celda, pulsa ⌘Z, guarda — git diff está vacío. Una implementación de restauración de instantáneas se vería correcta en pantalla mientras re-serializa silenciosamente cada fila que tocó.

Editar una celda; git diff muestra una sola línea cambiada

Respaldando esto: una verificación de huella digital se niega a sobrescribir cambios hechos a espaldas de OpenSheet, las escrituras pasan por un archivo temporal más os.replace(), y cada guardado mantiene un .bak junto a una instantánea al abrir.

Características

  • Tu dato es un archivo que posees — .jsonl simple, legible por jq, DuckDB, pandas, Excel y git

  • Deshacer todo — ⌘Z / ⇧⌘Z; un borrado por lotes se colapsa en un solo paso de deshacer

  • 13 tipos de campo — texto, número, selección, selección múltiple, fecha, casilla de verificación, URL, adjunto, fórmula, búsqueda entre tablas, hora de creación/actualización, auto-número. Los números se muestran como barras de progreso, moneda, calificaciones o porcentajes sin cambiar el valor almacenado

  • 4 tipos de vista — cuadrícula, kanban, galería, más filtros por vista, ordenamientos, agrupación, estadísticas, altura de fila, columnas congeladas y orden de columnas

  • 10,000 filas se mantienen fluidas — desplazamiento virtual; medido en 57 ms para cargar y 59 ms para guardar una tabla de 7.5 MB

  • Importar y exportar — entrada desde CSV, XLSX, JSON, SQLite y .grist; salida a CSV, XLSX, JSON, JSONL, Markdown y Parquet

  • Los adjuntos permanecen locales — los archivos van a <library>/assets/, la celda contiene una ruta relativa, nada se sube a ningún sitio

Hecho para agentes, no decorado con IA

Añadir un botón de IA a una hoja de cálculo es una característica. Elegir un formato de almacenamiento que un agente pueda leer y escribir sin un adaptador es una arquitectura. OpenSheet hizo lo segundo, y todo lo demás se deriva de ello: el archivo está orientado a líneas para que los añadidos sean >>, el formato es texto para que grep funcione, y el escritor es único para que la fidelidad de bytes sobreviva al acceso concurrente.

Un servidor MCP se ejecuta en el mismo proceso que el servidor HTTP, compartiendo una instancia de Store:

{
  "mcpServers": {
    "opensheet": {
      "command": "python3",
      "args": ["-m", "opensheet", "/path/to/libraries", "--mcp", "--mcp-root", "/path/to/libraries"],
      "env": { "PYTHONPATH": "/path/to/opensheet/src" }
    }
  }
}

Herramientas: list_libraries, list_tables, get_schema, query, upsert_rows. upsert_rows devuelve un recibo — contadores de inserted / updated / unchanged más las claves primarias para cada uno — y soporta dry_run. Las filas idénticas a lo que ya está en el disco cuentan como unchanged, y el archivo no se toca.

El mismo proceso no es un detalle de implementación. La fidelidad de bytes depende del estado en el proceso: en qué bytes llegó cada fila. Dos procesos que tengan cada uno su propia copia concluirían que las escrituras del otro son "cambios" y re-serializarían todo el archivo en el siguiente guardado. Un segundo proceso detecta el archivo de bloqueo y reenvía al primero, por lo que siempre hay exactamente un escritor.

Los agentes también pueden omitir OpenSheet y añadir al archivo directamente. Las reglas que mantienen la fidelidad intacta cuando lo hacen están documentadas en la guía de escritura directa.

Arquitectura

graph TD
    A["my-library/"] --> B["campaigns.jsonl<br/>source of truth"]
    A --> C["suppliers.jsonl"]
    A --> D[".opensheet/<br/>schema · views · links"]
    B --> E["store.py<br/>row passthrough · atomic write"]
    C --> E
    E --> F["single process"]
    F --> G["HTTP + browser UI"]
    F --> H["MCP over stdio"]
    G --> I["native macOS shell"]

.opensheet/ contiene tipos de campo, anchos de columna, definiciones de vista y enlaces entre tablas. Bórralo y pierdes formato, no datos — los tipos de campo caen en inferencia.

Por qué se mantiene pequeño

El backend es solo la biblioteca estándar de Python. El frontend es JavaScript puro — sin framework, sin paso de compilación. El shell de macOS es 184 KB de Swift sobre el WebKit del sistema, no un navegador empaquetado.

DuckDB es opcional y solo lectura, sirviendo el panel SQL y la exportación a Parquet. Nunca participa en filtrado, ordenamiento o agrupación, y nunca escribe. Cada escritura pasa por store.py.

Sin red, por construcción

Sin telemetría, sin comprobaciones de actualización, sin activos CDN, sin demo en línea. El navegador solo solicita rutas /api/* del mismo origen, el servidor se vincula solo al loopback IPv4, y el shell de escritorio no mantiene conexiones TCP propias. tests/test_offline.py hace cumplir todo esto.

Verificación

bash tests/opensheet-全量验收-20260815.sh

329 pruebas: 188 unitarias de JavaScript, 83 de Python, 42 de extremo a extremo en navegador (Playwright), 8 de ida y vuelta de fidelidad, 8 de ida y vuelta de biblioteca. Las pruebas de fidelidad comparan archivos byte por byte en lugar de campo por campo — una prueba que solo verificara valores pasaría mientras la promesa 1 se rompiera silenciosamente.

Las pruebas de navegador necesitan npm install dentro de web/ para el Chromium de Playwright.

Lo que OpenSheet no hará

Comentarios, permisos, colaboración en tiempo real, automatizaciones, una versión alojada, una demo en línea. Cada una de ellas necesita un sistema de cuentas o una dirección pública, lo que contradice la primera restricción de diseño: los datos nunca salen de tu máquina.

Este es un límite deliberado, no una brecha en la hoja de ruta.

Estado

Funciona y se usa a diario, con dos bordes ásperos que vale la pena conocer antes de probarlo:

  • La interfaz actualmente es solo en chino. El código, los comentarios y las cadenas de interfaz están todos en chino. La localización al inglés aún no se ha hecho.

  • Solo macOS para el shell de escritorio. La versión web funciona en cualquier lugar donde Python funcione.

Contribuir

Issues y PRs son bienvenidos. Dos cosas que saber antes de tocar la capa de almacenamiento:

  1. La lógica de paso de filas en store.py es el producto. Cambiarla significa mantener las pruebas de fidelidad en verde, y esas comparan bytes, no campos.

  2. Los comentarios de código están actualmente en chino. La ayuda con la traducción es muy bienvenida.

Licencia

MIT — ver LICENSE.

Available Tools

5 tools
get_schemaC

读取表字段 schema

NameRequiredDescriptionDefault
tableYes
libraryYes

TDQS

C2.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The verb '读取' indicates a read-only, non-mutating operation, which is useful since siblings include upsert_rows. However, with no annotations, the description carries the full burden and does not disclose return format, permissions, or potential errors, so transparency is only partial.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single short sentence with no filler, and the core action is front-loaded. It is concise, though slightly under-specified, which is more a completeness issue than a structure problem.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no annotations, no output schema, and 0% parameter description coverage, the definition leaves the agent without enough context about how to supply library/table values or what the returned schema will look like. Sibling names hint at a workflow, but the description itself does not establish it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%: the input schema only gives parameter names and types. The description mentions '表字段' (table fields) but leaves 'library' unexplained, and provides no value formats or how to obtain valid inputs, so it does not compensate for the missing schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description '读取表字段 schema' clearly states a read operation on a table's field schema, with a specific resource and scope. It is distinguishable from siblings like query (data retrieval) and list_tables (table enumeration), though it does not name them explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no guidance on when to use this tool instead of list_tables or query, and no exclusions or prerequisite steps are mentioned. The intended workflow (first list libraries/tables, then fetch schema) is only inferable from sibling names, not stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_librariesA

列出根目录内的 OpenSheet 库

NameRequiredDescriptionDefault

No parameters

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are present, so the description carries the full burden. It clearly indicates a read-only listing operation scoped to the root directory, but it does not disclose details such as pagination, sorting, whether nested libraries are included, or what the response shape is. For a no-parameter list operation, this is adequate but minimal.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single concise sentence that immediately communicates the action and scope. There is no filler or redundant information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the zero-parameter schema and no output schema, the description is nearly sufficient: it names the action, resource, and scope. Minor gaps include no statement about non-recursive behavior or return format, but the tool is simple enough that these are not critical.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so there is no schema burden to compensate for. The description appropriately focuses on output scope rather than parameter details, matching the baseline for parameterless tools.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('列出') and a specific resource ('根目录内的 OpenSheet 库'), clearly distinguishing this from siblings like list_tables, which lists tables rather than libraries. The scope 'root directory' adds useful precision.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description states what the tool does but gives no guidance on when to choose it over alternatives, nor any exclusions or prerequisites. An agent must infer from sibling names and the description that this is the tool for listing libraries, not tables or schemas.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_tablesB

列出库里的 JSONL 表

NameRequiredDescriptionDefault
libraryYes

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description bears the full burden. The verb '列出' implies a read-only listing operation, but the description does not disclose output format, pagination, error behavior, or whether any library validation occurs. It is minimally transparent but not richly so.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single short sentence with no redundant words. The operation and scope are front-loaded, making it easy to parse quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with one required parameter and no output schema, the description gives only minimal context. It does not explain what a 'JSONL 表' is exactly, what the agent should do with the returned list, or how to obtain a valid library value. The ambiguity around 'JSONL' and library selection leaves meaningful gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. The phrase '库里的' clarifies that the 'library' parameter identifies which library's tables are listed. However, it does not explain valid library identifier formats, whether values come from list_libraries, or how missing/invalid libraries are handled.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the operation ('列出' / list) and the resource ('JSONL 表' / tables) scoped to a library. It is easily distinguished from siblings like list_libraries, though it does not explicitly name the sibling it differs from.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is given on when to use this tool versus siblings such as get_schema, query, or list_libraries. The description only states what it does, not when it should be chosen or what prerequisite steps (like selecting a library) are needed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

queryB

用只读 DuckDB SQL 查询表

NameRequiredDescriptionDefault
sqlYes
tableYes
libraryYes

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It does disclose the critical read-only trait, which is essential for an agent to know this tool will not mutate data. It says nothing about return shape, SQL restrictions beyond read-only, error behavior, or permission requirements, so transparency is partial rather than complete.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single concise sentence with no filler. The key behavioral qualifier 'read-only' is front-loaded, and every word contributes meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with three required parameters, zero schema descriptions, and no annotations, the description is too sparse. An agent still lacks clarity about the 'library' parameter, whether results are returned in a specific format, and what SQL constructs are allowed beyond the read-only restriction.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the description adds little to parameter meaning beyond what the parameter names already imply. 'sql' and 'table' are self-explanatory, but 'library' remains ambiguous and there is no guidance on how the three parameters relate or what format the SQL should follow.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action—querying tables via DuckDB SQL—and explicitly marks it as read-only, which distinguishes it from upsert_rows. It does not explicitly name sibling tools or contrast its scope with list/get_schema tools, so it is clear but not maximally differentiated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The read-only qualifier implies this tool is for SELECT-style data retrieval and not for modifications, giving some usage direction. However, it does not explicitly state when to choose this over list_libraries, list_tables, or get_schema, leaving the routing mostly to inference from the tool name and siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

upsert_rowsA

按指定主键批量新增或更新,走与 HTTP 相同的 Store 并发保护。返回回执:inserted / updated / unchanged 计数与各自的主键值列表。dry_run=true 只算回执不落盘。

NameRequiredDescriptionDefault
keyYes
rowsYes
tableYes
dry_runNo只返回将发生的变更,不写文件
libraryYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full responsibility for behavior disclosure, and it delivers: it mentions Store concurrency protection, the exact receipt format (inserted/updated/unchanged counts and key lists), and the no-persistence behavior of dry_run=true. It does not cover error or validation behavior, but the most decision-relevant side effects are explicit.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three compact sentences cover the core operation, concurrency protection, return receipt, and dry-run behavior. The most essential verb and scope are front-loaded with no redundant filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description compensates for the missing output schema by stating the receipt shape, and it covers the operation's key nuances. It lacks row-structure details and failure semantics, which would help for a 5-parameter mutation tool, but it is sufficiently complete for a competent agent to call the tool correctly in the common case.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 20%, with only dry_run documented. The description adds meaning by identifying key as the primary key, rows as the batch payload, and clarifying dry_run semantics. However, it does not explain how rows should encode the key or what values library/table expect, leaving part of parameter construction to inference.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with '按指定主键批量新增或更新', a specific verb (upsert) and a clear resource (rows keyed by primary key). This immediately distinguishes it from the read-only and metadata sibling tools like query and list_tables, so an agent can tell what it does without needing more context.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description conveys that the tool is for batch insert-or-update operations by primary key and even highlights the dry_run inspection mode. However, it never explicitly contrasts it with alternatives such as query for reads or states when not to use it. The usage context is clear but the tool-selection guidance is only implied, not spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 5 tool updatesv0.1.0
    • First observedget_schema
    • First observedlist_libraries
    • First observedlist_tables
    • First observedquery
    • First observedupsert_rows

TDQS

A3.6/5.0

Scored across 5 tools

Disambiguation5/5

Each tool maps to a distinct action and resource level: libraries, tables, schema, query, and upsert. There is no meaningful overlap, and the descriptions reinforce the boundaries clearly.

Naming Consistency4/5

Most tool names follow a clear verb_noun snake_case pattern: list_libraries, list_tables, get_schema, upsert_rows. The single-word 'query' is a minor deviation, but the overall naming style remains uniform and predictable.

Tool Count5/5

Five tools is well-scoped for an OpenSheet data access server. Each tool covers a necessary step in the workflow without redundancy or bloat.

Completeness4/5

The set covers the core workflow well: discovering libraries, listing tables, inspecting schema, querying data, and upserting rows. The main gap is the lack of any delete or schema-mutation capability, but that may be intentionally out of scope for this server.

Maintenance

ActivityStale
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Turns a folder of CSV, Parquet, and JSON files into a single SQL-queryable source for AI agents, supporting JOINs across files with read-only sandboxed access.
    6
    22 PyPI
    2
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Enables AI assistants to read, write, query, and manage JSON data files with automatic ID and timestamp generation.
    6
    14 npm
    1
    MIT
  • A
    license
    B
    quality
    D
    maintenance
    Enables AI agents to interact with local SQLite databases with full CRUD, schema introspection, foreign key relations, generated columns, and multi-format import/export (CSV, JSON, XLSX) through natural language.
    26
    9 npm
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to keep structured, typed records in SQLite sheets with stable row ids, versions, and per-write audit history, so data survives across sessions and multiple agents. Lookups are fuzzy with an explicit match status, writes are version-checked and dry-run by default, and sheets can be created, queried, searched, and analyzed through MCP tools.
    -